两个python池,两个队列

时间:2016-07-22 22:07:55

标签: python queue pool

我试图理解池和队列在Python中是如何工作的,以下示例并不像预期的那样工作。我希望程序能够结束,但它会陷入无限循环,因为第二个队列没有被清空。

import multiprocessing
import os
import time

inq = multiprocessing.Queue()
outq = multiprocessing.Queue()

def worker_main(q1, q2):
    while True:
        i = q1.get(True)
        time.sleep(.1) 
        q2.put(i*2)

def worker2(q):
    print q.get(True)

p1 = multiprocessing.Pool(3, worker_main,(inq, outq,))
p2 = multiprocessing.Pool(2, worker2,(outq,))


for i in range(50):
    inq.put(i)


while inq.qsize()>0 or outq.qsize()>0:
    print 'q1 size', inq.qsize(), 'q2 size', outq.qsize()
    time.sleep(.1)

输出显示第二个队列(outq)是.get一次,但这都是。

输出:

q1 size 49 q2 size 0
q1 size 47 q2 size 0
2
4
q1 size 44 q2 size 1
q1 size 41 q2 size 4
q1 size 38 q2 size 7
q1 size 35 q2 size 11
q1 size 31 q2 size 14
q1 size 27 q2 size 18
q1 size 24 q2 size 21
q1 size 22 q2 size 23
q1 size 19 q2 size 26
q1 size 15 q2 size 30
q1 size 12 q2 size

为什么在outq为空之前,worker2是否被调用?

1 个答案:

答案 0 :(得分:4)

使用Pool这是一种非常奇怪的方式。传递给构造函数的函数仅在池中的每个进程调用一次。它适用于一次性初始化任务,很少使用。

按原样,您的worker2被调用两次,对于p2池中的每个进程一次。您的函数从队列中获取一个值,然后退出。这个过程永远不会做任何事情。所以它完全按照你的编码来做。

没有明显的理由在这里使用Pool;相反,创建5个multiprocessing.Process对象会更自然。

如果你觉得你必须这样做,那么你需要在worker2中加一个循环。这是一种方式:

import multiprocessing
import time

def worker_main(q1, q2):
    while True:
        i = q1.get()
        if i is None:
            break
        time.sleep(.1) 
        q2.put(i*2)

def worker2(q):
    while True:
        print(q.get())

if __name__ == "__main__":
    inq = multiprocessing.Queue()
    outq = multiprocessing.Queue()
    p1 = multiprocessing.Pool(3, worker_main,(inq, outq,))
    p2 = multiprocessing.Pool(2, worker2,(outq,))

    for i in range(50):
        inq.put(i)
    for i in range(3): # tell worker_main we're done
        inq.put(None)

    while inq.qsize()>0 or outq.qsize()>0:
        print('q1 size', inq.qsize(), 'q2 size', outq.qsize())
        time.sleep(.1)

建议的

这是一种“更自然”的方式来代替使用Process个对象,并使用队列标记(特殊值 - 此处None)让进程知道何时停止。顺便说一下,我使用的是Python 3,所以使用print作为函数而不是语句。

import multiprocessing as mp
import time

def worker_main(q1, q2):
    while True:
        i = q1.get()
        if i is None:
            break
        time.sleep(.1) 
        q2.put(i*2)

def worker2(q):
    while True:
        i = q.get()
        if i is None:
            break
        print(i)

def wait(procs):
    alive_count = len(procs)
    while alive_count:
        alive_count = 0
        for p in procs:
            if p.is_alive():
                p.join(timeout=0.1)
                print('q1 size', inq.qsize(), 'q2 size', outq.qsize())
                alive_count += 1

if __name__ == "__main__":
    inq = mp.Queue()
    outq = mp.Queue()
    p1s = [mp.Process(target=worker_main, args=(inq, outq,))
           for i in range(3)]
    p2s = [mp.Process(target=worker2, args=(outq,))
           for i in range(2)]
    for p in p1s + p2s:
        p.start()

    for i in range(50):
        inq.put(i)
    for p in p1s: # tell worker_main we're done
        inq.put(None)

    wait(p1s)
    # Tell worker2 we're done
    for p in p2s:
        outq.put(None)
    wait(p2s)