我有一套命令行工具,我想在一系列文件上并行运行。我写了一个python函数来包装它们看起来像这样:
def process_file(fn):
print os.getpid()
cmd1 = "echo "+fn
p = subprocess.Popen(shlex.split(cmd1))
# after cmd1 finishes
other_python_function_to_do_something_to_file(fn)
cmd2 = "echo "+fn
p = subprocess.Popen(shlex.split(cmd2))
print "finish"
if __name__=="__main__":
import multiprocessing
p = multiprocessing.Pool()
for fn in files:
RETURN = p.apply_async(process_file,args=(fn,),kwds={some_kwds})
虽然这有效,但它似乎没有运行多个进程;看起来它只是串行运行(我尝试使用Pool(5)
得到相同的结果)。我错过了什么?调用Popen
“阻止”吗?
EDIT2:上面的输出具有模式:
pid
finish
pid
finish
pid
finish
而类似的通话,使用map
代替apply
(但没有任何传递kwds
的规定)看起来更像
pid
pid
pid
finish
finish
finish
然而,地图通话有时(总是?)在显然成功之后挂起
答案 0 :(得分:4)
对
Popen
的呼叫是否“阻止”?
没有。只需创建subprocess.Popen
即可立即返回,为您提供一个可以等待或以其他方式使用的对象。如果你想阻止,那很简单:
subprocess.check_call(shlex.split(cmd1))
与此同时,我不确定你为什么要将你的args放在一个字符串中,然后尝试shlex
将它们放回到列表中。为什么不写清单?
cmd1 = ["echo", fn]
subprocess.check_call(cmd1)
虽然这有效,但它似乎没有运行多个进程;好像它只是在串行中运行
是什么让你这么想?鉴于每个进程只是尽可能快地将两个进程启动到后台,所以很难判断它们是否并行运行。
如果您想验证您是否从多个处理中获得了工作,您可能需要添加一些打印或记录(并在消息中添加os.getpid()
之类的内容)。
与此同时,您似乎试图将multiprocessing.Pool.map_async
的效果完全复制到multiprocessing.Pool.apply_async
的循环中,除了不是累积结果而是将每个变量存储在变量中叫RESULT
,然后在你可以使用它之前扔掉它。为什么不使用map_async
?
最后,您询问multiprocessing
是否适合该工作。好吧,你显然需要异步的东西:check_call(args(file1))
必须阻止other_python_function_to_do_something_to_file(file1)
,但同时不阻止check_call(args(file2))
。
我可能会使用threading
,但实际上,它并没有太大的区别。即使您处于流程启动成本高昂的平台上,您也已经支付了这笔费用,因为整个点都在运行N * M个子流程,因此另一个8流池不会伤害任何东西。并且通过在线程之间共享数据意外创建竞争的风险很小,或者意外地创建看起来像是在没有进程的进程之间共享数据的代码,因为没有什么可以共享。所以,无论你喜欢哪一个,都去吧。
另一种选择是编写一个事件循环。我可能真的开始为这个问题做自己,但我后悔了,你不应该这样做......