V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
sbmzhcn
V2EX  ›  Python

python 多线程在 while True:里的操作方式

  •  
  •   sbmzhcn · 2015-07-15 19:16:44 +08:00 · 5674 次点击
    这是一个创建于 3454 天前的主题,其中的信息可能已经有所发展或是发生改变。
    import queue
    import threading
    import datetime
    import time
    
    
    class RegistWorkerFactory():
        def __init__(self, domain=None):
            self.domain = domain
            self.addtime = datetime.datetime.now()
    
        def get_worker(self):
            print("get work, start registing....")
            if (datetime.datetime.now() - self.addtime).seconds > 60:
                return False
            return ParseCommand(self.domain)
    
    
    class ParseCommand(threading.Thread):
        def __init__(self, domain=None):
            threading.Thread.__init__(self)
            self.domain = domain
    
        def run(self):
            print("start parse {0}".format(self.domain))
    
    
    class Test():
        def __init__(self):
            self.workers = queue.Queue()
            # put
            self.workers.put(RegistWorkerFactory('domain1.com'))
            self.workers.put(RegistWorkerFactory('domain2.org'))
    
        def run(self):
            while True:
                threads = []
                for i in range(self.workers.qsize()):
                    temp = self.workers.get()
                    thread = temp.get_worker()
                    if thread:
                        # thread <ParseCommand(Thread-85, initial)> 会不停的从Thread-1增加
                        print("thread", thread)
                        self.workers.put(temp)
                        threads.append(thread)
    
                for t in threads:
                    time.sleep(.2)
                    t.start()
    
                # for t in threads:
                    # t.join()
    
                time.sleep(1)
                print("\n{} - {}\n".format(datetime.datetime.now(), '*'*50))
    
    notify = Test()
    notify.run()
    

    上面的代码也能运行,我本来是想写一个抢注域名的程序。我对于线程不太了解。在类Test中我,我希望 Test.workers这个队列中如果有域名就开始运行
    在这个地方:

    for t in threads:
    time.sleep(.2)
    t.start()

    但是在while True中,print("thread", thread) 这句代码打印的结果会是
    thread <ParseCommand(Thread-1, initial)>
    thread <ParseCommand(Thread-2, initial)>
    。。。。
    。。。。
    thread <ParseCommand(Thread-85, initial)>

    我想要应该是每次循环,它执行一次,然后下一个循环重新执行。这是不是错了?

    8 条回复    2015-07-16 11:21:27 +08:00
    wangyongbo
        1
    wangyongbo  
       2015-07-15 21:07:41 +08:00
    thread = temp.get_worker()
    每一次调用get_worker 都会
    return ParseCommand(self.domain)
    这句话创建了一个新的线程。

    所以线程数会增加。
    lyhapple
        2
    lyhapple  
       2015-07-15 21:24:09 +08:00
    看到python的多线程我就黯然神伤,唉。GIL苦啊
    sbmzhcn
        3
    sbmzhcn  
    OP
       2015-07-15 21:43:39 +08:00
    @wangyongbo 能否避免线程数增加。 另外 这样写有问题吗?
    wangyongbo
        4
    wangyongbo  
       2015-07-15 22:28:32 +08:00
    @sbmzhcn 这样写,我认为有问题

    1、每次都要创建新线程,白白消耗时间。

    2、 我认为你应该在ParseCommand 的run 函数里,循环检查是否这个域名是否已经注册过了。

    在notify 里检查 各个线程的状态。

    3、可以给RegistWorkerFactory 增加一个变量,self.thread 保存下来 创建的ParseCommand

    这样以后再get_worker 直接返回self.thread 就好了。不过你现在的写法,ParseCommand 的run 函数只打印一下就结束了,这个线程就退出了。
    aec4d
        5
    aec4d  
       2015-07-15 22:42:11 +08:00
    想到一个笑话 一个50行的程序大家都会来指指点点 一个500行的程序大家都会说好好好~~
    估计楼主最开始不是写python的
    这应该是一个生产者消费者模型,使用一个线程不断的查询可以注册的域名 添加到Queue队列,然后消费者线程不断的循环 就能后在queuq有数据的时候消耗掉它
    thread <ParseCommand(Thread-85, initial)> 会不停的从Thread-1增加
    至于这里
    self.workers.qsize()返回的总是2 然后你每次从queue中get一个出来之后都会在put一个进去一模一样的,当然会不间断的死循环了
    这个例子比较有趣~~
    http://stackoverflow.com/questions/20783337/concurrent-futures-usage-guide-a-simple-example-of-using-both-threading-and-pr
    magicyu1986
        6
    magicyu1986  
       2015-07-15 23:14:51 +08:00
    额,感觉写的略微有点麻烦。
    建议用一个阻塞队列,每次队列里有值的时候就拿出来启动一个线程注册,没有值就在While循环里阻塞。
    sbmzhcn
        7
    sbmzhcn  
    OP
       2015-07-16 09:12:40 +08:00
    @wangyongbo @aec4d workers这个队列是变动的。我只是测试就加了两个而已。在While True里其实是有一个监听,如果有新域名过来就加入到队列中,然后看队列中有多少个域名(这个域名数量一般不会很多,因为这些域名只是待抢注的域名),然后开始不停的注册(域名抢注,可能域名已经过期,但可不可以注册需要不停的去查询),只到注册成功,或者超时一个小时就停止。

    @magicyu1986 如果阻塞的话会影响外部的循环吧。

    如果有10个域名要抢注,我用线程,应该是可以同时注册的,这样比较好一点。

    @wangyongbo 虽然每次创建线程,但如果不影响效率也没问题吧。


    @aec4d 不至于死循环,无论里面有多少个域名,如果超时过2个小时队列就会为空。self.workers.qsize()是动态变化的,上面的代码只是一个简化的例子,我加了两个而已。
    magicyu1986
        8
    magicyu1986  
       2015-07-16 11:21:27 +08:00
    @sbmzhcn 向队列添加的逻辑要放到另外一个线程中,可以理解为两个线程,一个添加,一个干活,中间用一个阻塞队列连接起来了。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2625 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 07:08 · PVG 15:08 · LAX 23:08 · JFK 02:08
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.