我在Python 3中编写内容以从站点获取代理并检查代理是否有效。 我使用队列和线程模块来加快检查过程。 然而,后果很奇怪。
def worker():
while True:
item = q.get()
do_work(item)
q.task_done()
q = Queue()
for i in range(num_worker_threads):
t = Thread(target=worker)
t.daemon = True
t.start()
for item in source():
q.put(item)
q.join()
这是队列文档中的一个示例。我的代码基于这个例子。
所以,我的问题是: worker()中的while循环何时结束?
当队列中的项目数超过200时,q保持块代码,队列中的1个项目无法处理,1个线程继续执行q.get(),而其他线程则说q是空。
请帮帮我。谢谢。 抱歉我的英语不好。我还在努力。
----更新------------------------------------------ ---------------------------
我尝试过ThreadPoolExecutor,它起作用,就像线程和队列一样。但是封锁的情况并没有改变。
比赛结束20分钟后,代码的一次试运行结束并打印出预期的输出。
我发现检查程序在2或3分钟内完成(对于100个代理),代码在结束前大约10分钟就会阻塞。
第二个问题: 可能导致此问题的原因是什么?
谢谢! :)
----更新------------------------------------------ ----------------------------
问题解决了!!
我认为导致阻塞的是线程,但事实证明连接和传输时间是因果关系。
由于我使用pycurl进行代理检查,而pycurl的默认TIMEOUT为300。
我只将CONNECTTIMEOUT设置为5并忽略TIMEOUT,这限制了整个传输时间。
这是我用于代理检查的新代码:
c = pycurl.Curl()
c.setopt(c.URL, url)
c.setopt(c.HTTPHEADER, headers)
c.setopt(c.PROXY, proxy)
c.setopt(c.WRITEFUNCTION, lambda x: None)
c.setopt(c.CONNECTTIMEOUT, 5)
*c.setopt(c.TIMEOUT, 5)*
c.perform()
c.close()
但是,将TIMEOUT设置为5会显着减少有效代理的数量。我将继续努力寻找最佳的TIMEOUT价值。
答案 0 :(得分:1)
没有类似的while True
循环永远不会结束,你的线程永远不会退出。您必须明确说明您的线程何时退出。
这样做的方法是使用哨兵,如下:
end_of_queue = object()
def worker():
while True:
item = q.get()
if item is end_of_queue:
q.task_done()
break
do_work(item)
q.task_done()
q = Queue()
for i in range(num_worker_threads):
t = Thread(target=worker)
t.daemon = True
t.start()
for item in source():
q.put(item)
for i in range(num_worker_threads):
q.put(end_of_queue)
q.join()
我在这里做的是在队列中添加一些end_of_queue
元素,每个线程一个。当一个线程看到这个end_of_queue
对象时,就意味着它必须退出并且可以突破循环。
如果您更喜欢不同的方法,可以考虑使用Event
object在必须退出时通知线程,如下所示:
quit_event = Event()
def worker():
while not q.empty() or not quit_event.is_set():
try:
item = q.get(timeout=.1)
except Empty:
continue
do_work(item)
q.task_done()
q = Queue()
for i in range(num_worker_threads):
t = Thread(target=worker)
t.daemon = True
t.start()
for item in source():
q.put(item)
quit_event.set()
q.join()
此解决方案的缺点是您必须get()
超时。
最后但并非最不重要的是,您的代码似乎可以从使用thread pool中受益,如下所示:
with ThreadPoolExecutor(max_workers=num_worker_threads) as executor:
executor.map(do_work, source())
(作为参考,ThreadPoolExecutor
uses the end_of_queue
approach,唯一的两个区别是end_of_queue
是None
,每个线程负责通知其他线程。)
答案 1 :(得分:0)
另一个使用类
中的线程,队列和循环的例子import threading
import Queue
q = Queue.Queue()
class listener(object):
def __init__(self):
thread = threading.Thread(target=self.loop)
# thread.daemon = True
thread.start()
def loop(self):
for i in xrange(0,13):
q.put(i)
class ui(object):
def __init__(self):
listener()
while True:
item = q.get()
print item
if item == 10:
break
ui()