JoinableQueue join()方法甚至在task_done()之后阻塞主线程

时间:2016-08-19 09:15:00

标签: python multiprocessing

在下面的代码中,如果我放daemon = True,则在读取所有队列条目之前,使用者将退出。如果使用者是非守护进程,则即使在所有条目的task_done()之后,主线程也始终被阻止。

from multiprocessing import Process, JoinableQueue

import time


def consumer(queue):
    while True:
        final = queue.get()
        print (final)
        queue.task_done()


def producer1(queue):
    for i in "QWERTYUIOPASDFGHJKLZXCVBNM":
        queue.put(i)

if __name__ == "__main__":

    queue = JoinableQueue(maxsize=100)
    p1 = Process(target=consumer, args=((queue),))
    p2 = Process(target=producer1, args=((queue),))
    #p1.daemon = True
    p1.start()
    p2.start()
    print(p1.is_alive())
    print (p2.is_alive())
    for i in range(1, 10):
        queue.put(i)
        time.sleep(0.01)
    queue.join()

1 个答案:

答案 0 :(得分:0)

让我们看看 - 我相信 - 在这里发生了什么:

  1. 两个流程正在启动。
  2. consumer进程开始循环并阻塞,直到从队列中收到一个值。
  3. producer1进程使用字母为队列提供26次,而主进程使用数字向队列提供9次。不保证字母或数字的输入顺序 - 在一封信之前可以很好地显示一个数字。
  4. producer1和主进程都完成了提供数据时,队列正在加入。没问题,队列可以加入,因为所有缓冲的数据都已被使用,每次读取后都调用了task_done()
  5. consumer进程仍在运行但被阻止,直到显示更多要消耗的数据。
  6. 查看您的代码,我相信您将加入流程的概念与加入队列的概念相混淆。你最想要的是加入流程,你可能根本不需要一个可连接的队列。

    #!/usr/bin/env python3
    
    from multiprocessing import Process, Queue
    
    import time
    
    def consumer(queue):
        for final in iter(queue.get, 'STOP'):
            print(final)
    
    def producer1(queue):
        for i in "QWERTYUIOPASDFGHJKLZXCVBNM":
            queue.put(i)
    
    if __name__ == "__main__":
        queue = Queue(maxsize=100)
        p1 = Process(target=consumer, args=((queue),))
        p2 = Process(target=producer1, args=((queue),))
        p1.start()
        p2.start()
        print(p1.is_alive())
        print(p2.is_alive())
        for i in range(1, 10):
            queue.put(i)
            time.sleep(0.01)
        queue.put('STOP')
        p1.join()
        p2.join()
    

    同样,您的producer1在提供所有字母后自行退出,但您需要一种方法告诉您的consumer进程退出,因为它不再需要处理的数据。你可以通过发送一个哨兵来做到这一点,在这里我选择了字符串'STOP',但它可以是任何东西。

    事实上,这段代码不是很好,因为在某些字母之前可能会收到'STOP'哨兵,因此两者都会导致某些字母无法处理,但也会导致死锁,因为即使队列正在尝试加入进程仍然包含一些数据。但这是一个不同的问题。