我在Python中使用multiprocessing
模块并期望启动流程,创建队列以及从队列中放入和获取值。但是,如果子流程有足够的工作要做,我预计开销最终会被淘汰。运行一个简单的例子(如下所述),我生成的进程的运行时间大约是从父进程启动的同一进程的10倍,即使对于非常大的作业也是如此。
在下面的代码中,我计算了一系列越来越大的数组的平均值。我比较从父进程调用numpy.mean
到从单个生成进程调用相同的mean函数,并在生成的进程中做任何事情(以了解开销成本)。
最初,结果如我所料。从父进程调用mean
时,与从生成进程调用%matplotlib
import numpy, multiprocessing, pandas
def do_nothing(x,q):
q.put(x[-1])
def my_mean(x,q):
q.put(numpy.mean(x))
def test_mp(f,x):
q = multiprocessing.Queue()
p = multiprocessing.Process(target=f,args=(x,q))
p.start()
p.join()
s = q.get()
return s
ndata = 2**numpy.arange(10,29,2)
tr1,tr2,tr3 = [[],[],[]]
for n in ndata:
x = numpy.random.rand(n)
tresults = %timeit -n 1 -r 5 -o -q test_mp(do_nothing,x)
tr1.append(tresults)
tresults = %timeit -n 1 -r 5 -o -q test_mp(my_mean,x)
tr2.append(tresults)
tresults = %timeit -n 1 -r 5 -o -q numpy.mean(x)
tr3.append(tresults)
print("All done")
t1,t2,t3 = map(lambda tr : pandas.Series([1000*t.best for t in tr]),[tr1,tr2,tr3])
df = pandas.DataFrame({'n' : ndata, 't1 (do nothing)' : t1,
't2 (my_mean)' : t2,
't3 (mean)' : t3})
display(df)
df.plot(x='n',style='.-',markersize=10,logx=True,logy=True)
时相比,总运行时间要快得多。对于小型作业,生成的进程的运行时由开销主导。
然而,令人惊讶的是,对于较大的作业,衍生过程的运行时间始终超过从父进程调用大约10倍的成本。
有人可以为此提供解释吗?这是由于子流程中的内存限制吗?我测试的最大阵列是125MB,500MB和2GB。
以下是代码:
ant
以下是结果。所有计时结果都以毫秒为单位。
答案 0 :(得分:0)
以下是对正在发生的事情的一些观察:
使用-c
中的%timeit
标记仅显示父进程的CPU时间,在这种情况下,my_mean
和do_nothing
显示基本相同的单位倍。因此父进程在两种情况下都使用相同的CPU时间。
如果没有-c
标记,则会计算酸洗过程中的时间,至少在调用my_mean
时。为什么do_nothing
中没有考虑它仍然是一个谜。 Python解释器是否足够智能以识别do_nothing
什么都不做?
还有什么神秘之处:谁在做酸洗?父进程?如果是这样,它不会占用任何CPU时间。所以它必须是衍生过程。
使用线程模块(使用queue.Queue()
和threading.Thread()
,结果更符合预期,即对于足够大的问题,运行时间由所需时间决定计算平均值,对numpy.mean()
的调用和生成过程中的同一调用基本上是同一时间。
以下是使用线程模块解决同一问题的时间: