使用队列时等待Python进程完成的简单而安全的方法

时间:2016-02-26 18:18:13

标签: python

我使用import matplotlib import matplotlib.pyplot as plt from datetime import datetime x_orig = ['2015-12-29 15:01:25', '2015-12-29 15:02:08', '2015-12-29 15:02:13', '2015-12-29 15:04:18'] x = [datetime.strptime(d, '%Y-%m-%d %H:%M:%S') for d in x_orig] y = ['7.1', '7.4', '9.4', '10.2'] xs = matplotlib.dates.date2num(x) hfmt = matplotlib.dates.DateFormatter('%Y-%m-%d\n%H:%M:%S') fig = plt.figure() ax = fig.add_subplot(1,1,1) ax.patch.set_facecolor('lightgrey') ax.xaxis.set_major_formatter(hfmt) ax.set_title('Titel des Reports') ax.set_xlabel('datum') ax.set_ylabel('2MTemperatur') plt.setp(ax.get_xticklabels(), size=8) ax.plot(xs, y, linewidth=2) ax.scatter(xs, y) plt.grid() plt.show() 类来创建和管理子进程,这可能会返回非繁琐的数据量。该文档指出Process是等待join()完成(https://docs.python.org/2/library/multiprocessing.html#the-process-class)的正确方法。

但是,使用Process时,如果加入流程会导致挂起,如下所述:https://bugs.python.org/issue8426和此处https://docs.python.org/2/library/multiprocessing.html#multiprocessing-programming(不是错误)。

这些文档建议删除multiprocessing.Queue - 但这肯定会删除所有流程已完成的保证,因为p.join()只等待单个项目可用?

在这种情况下,如何等待所有Queue.get() es的完成,并确保我收集所有Process的输出?

我想要处理的一个简单例子:

from multiprocessing import Process, Queue

class MyClass:
    def __init__(self):
        pass


def example_run(output):
    output.put([MyClass() for i in range(1000)])
    print("Bottom of example_run() - note hangs after this is printed")


if __name__ == '__main__':

    output = Queue()
    processes = [Process(target=example_run, args=(output,)) for x in range(5)]

    for p in processes:
        p.start()

    for p in processes:
        p.join()

    print("Processes completed")

2 个答案:

答案 0 :(得分:0)

  

https://bugs.python.org/issue8426   这意味着无论何时使用队列,您都需要确保这一点   所有已放入队列的项目最终都将被删除   在流程加入之前。否则你不能确定   将项目放入队列的进程将终止。

在您的示例中,我在调用output.get()之前添加了join(),并且每件事情都运行良好。我们将数据放入队列中以便在某些地方使用,所以只需确保。

for p in processes:
    p.start()
print output.get()
for p in processes:
    p.join()

print("Processes completed")

答案 1 :(得分:0)

一个不优雅的解决方案是添加

output_final = []
for i in range(5):  # we have 5 processes
    output_final.append(output.get())
在尝试加入任何进程之前

。这只是试图为我们已经开始的流程数量获得适当数量的输出。

结果是更好,更广泛的解决方案根本不使用Process;请改用Pool。这样就可以为您处理启动工作流程和收集结果的麻烦:

import multiprocessing

class MyClass:
    def __init__(self):
        pass

def example_run(someArbitraryInput):
    foo = [MyClass() for i in range(10000)]
    return foo

if __name__ == '__main__':

    pool = multiprocessing.Pool(processes=5)
    output = pool.map(example_run, range(5))
    pool.close();  pool.join()  # make sure the processes are complete and tidy
    print("Processes completed")