使用多处理模块的脚本不会终止

wil*_*007 8 python multiprocessing python-2.7 python-multiprocessing

以下代码不打印"here".问题是什么?我在我的两台机器上测试了它(Windows 7,Ubuntu 12.10)和 http://www.compileonline.com/execute_python_online.php 它并不是"here"在所有情况下打印.

from multiprocessing import Queue, Process


def runLang(que):
    print "start"
    myDict=dict()
    for i in xrange(10000):
        myDict[i]=i
    que.put(myDict)
    print "finish"


def run(fileToAnalyze):
    que=Queue()
    processList=[]
    dicList=[]
    langs= ["chi","eng"]
    for lang in langs:
        p=Process(target=runLang,args=(que,))
        processList.append(p)
        p.start()

    for p1 in processList:
        p1.join()

    print "here"

    for _ in xrange(len(langs)):
        item=que.get()
        print item
        dicList.append(item)

if __name__=="__main__":
    processList = []
    for fileToAnalyse in ["abc.txt","def.txt"]:
        p=Process(target=run,args=(fileToAnalyse,))
        processList.append(p)
        p.start()
    for p1 in processList:
        p1.join()
Run Code Online (Sandbox Code Playgroud)

dan*_*ano 15

这是因为当你将put很多项目放入a时multiprocessing.Queue,一旦底层Pipe已满,它们最终会被缓冲在内存中.缓冲区将不会被刷新,直到某些东西从另一端开始读取Queue,这将允许Pipe接受更多数据.Process在所有Queue实例的缓冲区已完全刷新到其底层之前,A 无法终止Pipe.这意味着如果你尝试join进程而没有另一个进程/线程调用get它Queue,你可能会死锁.这在文档中提到:

警告

如上所述,如果子进程已将项目放入队列(并且尚未使用JoinableQueue.cancel_join_thread),则在将所有缓冲的项目刷新到管道之前,该进程不会终止.

这意味着,如果您尝试加入该进程,则可能会遇到死锁,除非您确定已经使用了已放入队列的所有项目.类似地,如果子进程是非守护进程,则父进程在尝试加入其所有非守护进程子进程时可能会在退出时挂起.

请注意,使用管理器创建的队列没有此问题.

您可以通过在父级中join清空之前不调用来解决问题Queue:

for _ in xrange(len(langs)):
    item = que.get()
    print(item)
    dicList.append(item)

# join after emptying the queue.
for p in processList:
    p.join()

print("here")
Run Code Online (Sandbox Code Playgroud)