队列和线程,而线程

时间:2016-01-07 12:20:53

标签: python multithreading python-3.x pycurl

我在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价值。

2 个答案:

答案 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_queueNone,每个线程负责通知其他线程。)

答案 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()