subprocess + multiprocessing - 顺序的多个命令

时间:2012-11-07 23:04:24

标签: python multiprocessing

我有一套命令行工具,我想在一系列文件上并行运行。我写了一个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“阻止”吗?

编辑:澄清一点。我需要cmd1,然后是一些python命令,然后是cmd2,以便在每个文件上按顺序执行。

EDIT2:上面的输出具有模式:

pid
finish
pid
finish
pid
finish

而类似的通话,使用map代替apply(但没有任何传递kwds的规定)看起来更像

pid
pid
pid
finish
finish
finish

然而,地图通话有时(总是?)在显然成功之后挂起

1 个答案:

答案 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流池不会伤害任何东西。并且通过在线程之间共享数据意外创建竞争的风险很小,或者意外地创建看起来像是在没有进程的进程之间共享数据的代码,因为没有什么可以共享。所以,无论你喜欢哪一个,都去吧。

另一种选择是编写一个事件循环。我可能真的开始为这个问题做自己,但我后悔了,你不应该这样做......