Python numpy和多处理队列的组合会扰乱队列的顺序

Python numpy和多处理队列的组合会扰乱队列的顺序,python,numpy,queue,multiprocessing,task-queue,Python,Numpy,Queue,Multiprocessing,Task Queue,我使用以下模式进行多重处理: for item in data: inQ.put(item) for i in xrange(nProcesses): inQ.put('STOP') multiprocessing.Process(target=worker, args=(inQ, outQ)).start() inQ.join() outQ.put('STOP') for result in iter

我使用以下模式进行多重处理:

    for item in data:
        inQ.put(item)

    for i in xrange(nProcesses):
        inQ.put('STOP')
        multiprocessing.Process(target=worker, args=(inQ, outQ)).start()

    inQ.join()
    outQ.put('STOP')

    for result in iter(outQ.get, 'STOP'):
        # save result
这很好用。但是,如果我通过
outQ
发送numpy数组,则
的“停止”
不会在
outQ
的末尾结束,从而导致结果获取循环提前终止

下面是一些代码来重现巴哈维奥

import multiprocessing
import numpy as np

def worker(inQ, outQ):
    for i in iter(inQ.get, 'STOP'):
        result = np.random.rand(1,100)
        outQ.put(result)
        inQ.task_done()
    inQ.task_done() # for the 'STOP'

def main():
    nProcesses = 8
    data = range(1000)

    inQ = multiprocessing.JoinableQueue()
    outQ = multiprocessing.Queue()
    for item in data:
        inQ.put(item)

    for i in xrange(nProcesses):
        inQ.put('STOP')
        multiprocessing.Process(target=worker, args=(inQ, outQ)).start()

    inQ.join()
    print outQ.qsize()
    outQ.put('STOP')

    cnt = 0
    for result in iter(outQ.get, 'STOP'):
        cnt += 1
    print "got %d items" % cnt
    print outQ.qsize()

if __name__ == '__main__':
    main()
如果将
result=np.random.rand(1100)
替换为类似
result=i*i
的内容,则代码将按预期工作

这里发生了什么?我在这里犯了什么根本性的错误吗?我本来希望
inQ.join()
之后的
outQ.put()
能做我想做的事情,因为
join()
阻塞,直到所有进程都完成了所有
put()
s

对于我来说,解决方法是在outQ.qsize()>0的情况下使用
执行结果获取循环,这样可以查找。但是我读到
qsize()
是不可靠的。是否只有在不同进程运行时才不可靠?在完成了
inQ.join()
之后,我是否可以依靠
qsize()

我希望有人会建议使用
多处理.Pool.map()
,但在使用numpy数组(ndarray)时,我会遇到pickle错误


谢谢你看

numpy数组使用丰富的比较。因此a=='STOP'返回一个numpy数组,而不是bool,并且该numpy数组不能强制为bool。在幕后,iter(outQ.get,'STOP')正在进行这种比较,当它试图将结果转换为bool时,可能会将异常视为False。您必须执行手动while循环,从队列中提取项目,在将其与“STOP”进行比较之前检查是否存在isinstance(项目、基串)

while True:
    item = outQ.get()
    if isinstance(item, basestring) and item == 'STOP':
        break
    cnt += 1

检查qsize()可能也可以正常工作,因为在加入输入队列后,没有其他进程添加到队列中。

由于您知道从
outQ
中预期有多少项,另一个解决方法是显式等待该数量的项:

import multiprocessing as mp
import numpy as np
import Queue

N=100

def worker(inQ, outQ):
    while True:
        i,item=inQ.get()
        result = np.random.rand(1,N)
        outQ.put((i,result))
        inQ.task_done()

def main():
    nProcesses = 8
    data = range(N)
    inQ = mp.JoinableQueue()
    outQ = mp.Queue()    

    for i,item in enumerate(data):
        inQ.put((i,item))

    for i in xrange(nProcesses):
        proc=mp.Process(target=worker, args=[inQ, outQ])
        proc.daemon=True
        proc.start()

    inQ.join()
    cnt=0
    for _ in range(N):
        result=outQ.get()
        print(result)
        cnt+=1
        print(cnt)      
    print('got {c} items'.format(c=cnt))

if __name__ == '__main__':
    main()

你测试过它了吗,看看普通的旧线程。线程是否也有同样的问题?我先用线程,但我用它来读取tar.gz,它是用python实现的,这意味着线程将不会有帮助,因为GIL。使用线程和队列。队列似乎可以工作,是的。它为您解决了问题吗?不,看起来有其他问题。序列化结果项所需的时间可能会干扰远程进程中队列将其推入主进程的能力。因此,在所有结果实际出现之前,您将“STOP”添加到主进程中的队列中。试试Q.put([i]*1000),你会看到同样的效果。尝试“whilenotoutq.empty():”而不是使用“STOP”哨兵。避免使用.qSize(),因为它不适用于所有平台。您使用[i]*1000是正确的。我以为序列化会完成,当程序执行inQ.task_done()
时,为什么不是这样呢?我尝试了
empty()
,但也失败了。有时在
qsize()>0
中是正确的。我不明白幕后发生了什么。这并不能真正回答问题,但解决了问题。天啊,我早该发现的!多谢各位@unutbu:你真的用过那个模块吗?它看起来真的很凌乱。@chuck:我还没有必要在严肃的工作中使用它,但是上面的代码可以工作,是吗?对你来说,这个模块看起来很凌乱吗?乍一看,似乎有很多未被注释的代码行。它似乎需要Cython,我看不到任何文档,比如我在使用它时必须注意的东西。此外,自述文件似乎已损坏。你有过这样的经验吗?@unutbu:它对1000x10000个矩阵无效,也就是说只有80MB,我想至少达到10GB。我猜共享内存部分不够大?