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

2015-07-15 19:16:44 +08:00
 sbmzhcn
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)>

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

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

所以线程数会增加。
lyhapple
2015-07-15 21:24:09 +08:00
看到python的多线程我就黯然神伤,唉。GIL苦啊
sbmzhcn
2015-07-15 21:43:39 +08:00
@wangyongbo 能否避免线程数增加。 另外 这样写有问题吗?
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
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
2015-07-15 23:14:51 +08:00
额,感觉写的略微有点麻烦。
建议用一个阻塞队列,每次队列里有值的时候就拿出来启动一个线程注册,没有值就在While循环里阻塞。
sbmzhcn
2015-07-16 09:12:40 +08:00
@wangyongbo @aec4d workers这个队列是变动的。我只是测试就加了两个而已。在While True里其实是有一个监听,如果有新域名过来就加入到队列中,然后看队列中有多少个域名(这个域名数量一般不会很多,因为这些域名只是待抢注的域名),然后开始不停的注册(域名抢注,可能域名已经过期,但可不可以注册需要不停的去查询),只到注册成功,或者超时一个小时就停止。

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

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

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


@aec4d 不至于死循环,无论里面有多少个域名,如果超时过2个小时队列就会为空。self.workers.qsize()是动态变化的,上面的代码只是一个简化的例子,我加了两个而已。
magicyu1986
2015-07-16 11:21:27 +08:00
@sbmzhcn 向队列添加的逻辑要放到另外一个线程中,可以理解为两个线程,一个添加,一个干活,中间用一个阻塞队列连接起来了。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/205926

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX