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)>
我想要应该是每次循环,它执行一次,然后下一个循环重新执行。这是不是错了?
1
wangyongbo 2015-07-15 21:07:41 +08:00
thread = temp.get_worker()
每一次调用get_worker 都会 return ParseCommand(self.domain) 这句话创建了一个新的线程。 所以线程数会增加。 |
2
lyhapple 2015-07-15 21:24:09 +08:00
看到python的多线程我就黯然神伤,唉。GIL苦啊
|
3
sbmzhcn OP @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 函数只打印一下就结束了,这个线程就退出了。 |
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 |
6
magicyu1986 2015-07-15 23:14:51 +08:00
额,感觉写的略微有点麻烦。
建议用一个阻塞队列,每次队列里有值的时候就拿出来启动一个线程注册,没有值就在While循环里阻塞。 |
7
sbmzhcn OP @wangyongbo @aec4d workers这个队列是变动的。我只是测试就加了两个而已。在While True里其实是有一个监听,如果有新域名过来就加入到队列中,然后看队列中有多少个域名(这个域名数量一般不会很多,因为这些域名只是待抢注的域名),然后开始不停的注册(域名抢注,可能域名已经过期,但可不可以注册需要不停的去查询),只到注册成功,或者超时一个小时就停止。
@magicyu1986 如果阻塞的话会影响外部的循环吧。 如果有10个域名要抢注,我用线程,应该是可以同时注册的,这样比较好一点。 @wangyongbo 虽然每次创建线程,但如果不影响效率也没问题吧。 @aec4d 不至于死循环,无论里面有多少个域名,如果超时过2个小时队列就会为空。self.workers.qsize()是动态变化的,上面的代码只是一个简化的例子,我加了两个而已。 |
8
magicyu1986 2015-07-16 11:21:27 +08:00
@sbmzhcn 向队列添加的逻辑要放到另外一个线程中,可以理解为两个线程,一个添加,一个干活,中间用一个阻塞队列连接起来了。
|