Python中多线程时queue.queue的正确实现

Python中多线程时queue.queue的正确实现,python,multithreading,Python,Multithreading,我正在学习python,并编写了一些简单的脚本,为自己提供各种主题的实际示例。其中一个脚本演示了如何将queue.queue()与threading.Thread()一起使用来创建后台工作人员。不过,它的行为相当奇怪。我做了一些计时赛。只需一个线程,它就会像您所期望的那样。。。每项任务大约需要2秒(实际上不到40秒)才能完成这20项任务。有了四个线程,它会像您所期望的那样再次运行。它一次完成4项任务,因此大约需要10秒。那么,当我运行20个线程时,地球是如何运行的呢?它需要0.01秒(1s.f.

我正在学习python,并编写了一些简单的脚本,为自己提供各种主题的实际示例。其中一个脚本演示了如何将queue.queue()与threading.Thread()一起使用来创建后台工作人员。不过,它的行为相当奇怪。我做了一些计时赛。只需一个线程,它就会像您所期望的那样。。。每项任务大约需要2秒(实际上不到40秒)才能完成这20项任务。有了四个线程,它会像您所期望的那样再次运行。它一次完成4项任务,因此大约需要10秒。那么,当我运行20个线程时,地球是如何运行的呢?它需要0.01秒(1s.f.)——肯定需要2秒吗

代码如下:

import threading
from queue import Queue
import time

q = Queue()
tLock = threading.Lock()

def run() :

    while True :
        task = q.get()  
        print('Just finished task number',task)
        q.task_done()   
        time.sleep(2)

def main() :
    # worker threads are activated  
    for x in range(20) :
        t = threading.Thread(target=run)
        t.daemon = True
        t.start()
    #20 jobs are put in the queue   
    for x in range(1,21) :
        q.put(x)
    #waits until queue is empty and then continues
    q.join()

if __name__ == '__main__' :
    startTime = time.time()
    main()
    print('Time taken was', time.time() - startTime)

实际上,您并没有阻止主线程的进程:

“正确的”(*)方法是通过连接所有线程来确保完成所有线程:

def main() :
    # keep reference to threads
    threads = [threading.Thread(target=run) for _ in range(20)]
    # start all threads
    for t in threads:
        t.start()

    #20 jobs are put in the queue   
    for x in range(1,21) :
        q.put(x)
    #waits until queue is empty and then continues
    q.join()
    # join all threads
    for t in threads:
        t.join()
*但是,这将不起作用,因为线程处于无限循环中,即使任务已经完成

因此,另一种方法是确保在报告任务之前等待

def run() :
    while True :
        task = q.get()  
        # simulate processing time *before* actual reporting
        time.sleep(2)
        print('Just finished task number',task)  
        q.task_done()
不过,线程仍然被阻塞。你可以选择给线程一条消息,告诉他们退出。比如:

def run() :
    while True :
        task = q.get()
        if task == 'stop':
            break  
        # simulate processing time *before* actual reporting
        time.sleep(2)
        print('Just finished task number',task)  
        q.task_done()
现在只需告诉主线程放置足够的停止消息,以便所有线程最终退出其无限循环:

def main() :
    # keep reference to threads
    threads = [threading.Thread(target=run) for _ in range(20)]
    # start all threads
    for t in threads:
        t.start()

    #20 jobs are put in the queue   
    for x in range(1,21):
        q.put(x)

    for x in range(20):
        # stop all threads after tasks are done
        q.put('stop')

    # waits until queue is empty and then continues
    q.join()

    # join all threads
    for t in threads:
        t.join()

提示:你不应该使用“幻数”,如
20
。在模块级有一个名为
THREADS\u COUNT
的全局变量,因此,当您想测试不同的配置时,只需更改一个位置。

这是一个很好的答案,我一直将此作为我在该主题上的主要参考,因此编辑了标题,使其他人更容易看到它。谢谢,如果你有任何改进的建议,欢迎。