python multiprocessing:我可以建立一个将参数列表作为输入的进程池吗?

时间:2018-12-30 18:49:57

标签: python multiprocessing

因此,我有一个构建命令列表的脚本,然后将其提供给Popen以并行启动。这可以按我预期的那样工作-但我正在尝试编写一些可以同时运行有限数量(而不是全部)的东西。我已经走了这么远:

#! /usr/bin/env python3

import subprocess
from multiprocessing import Pool

cmd_list = []
cmd_list.append(['echo','zero', 'one'])
cmd_list.append(['echo','one'])
cmd_list.append(['echo','two'])    # and so on...

# each entry in cmd_list can now be run in a subprocess/subshell


pidlist = []

for cmd in cmd_list:
    pid = subprocess.Popen(cmd)
    pidlist.append(pid)

for cmd in cmd_list:
    pid.wait()

pool = Pool(2)    

## map or apply or queue or something here so I run only two "cmd"s until they're all done... 

我一直在疯狂地搜索,并使用mapapply以及worker和queues找到了很多示例,坦率地说,这似乎有点多-我认为我有足够的经验python知道必须有一种更简单的方法来解决此问题,而无需重新整理所有命令字符串(在我的情况下,它可以是数百个字符长,但是它们 都被格式化为您将列表传递给Popen,它将运行;-)

描述该行为的另一种方法在功能上等同于在unix xargs命令中使用-P <n>自变量...

编辑:想扩展此范围,以允许将一组args(kwargs)传递到池进程中。我现在有下面的代码块可以工作:

def spawn(cmd):
   pid = subprocess.Popen(cmd)
   pid.wait()

pool = Pool(3)    
pool.map(spawn, cmd_list)  # happily kicks of three subprocesses and runs...

但是我希望能够将其他参数传递给spawn调用,在这种特殊情况下,我希望能够将优先级或std {in,out,err}重定向之类的东西传递给Popen调用。我尽力在函数签名中尝试一堆** kwargs的不同组合,但是什么也做不了。我从这里开始,希望它能表达我所追求的行为:

def spawnWithOpts(cmd, **kwargs):   
   pid = subprocess.Popen(cmd, **kwargs)
   pid.wait()

pool.starmap(spawnWithOpts, cmd_list, "stderr=subprocess.STDOUT")

这等同于将spawn的定义更改为:

def spawn(cmd):
   pid = subprocess.Popen(cmd, stderr=subprocess.STDOUT)
   pid.wait()

但是,显然,我希望能够根据我所遵循的确切行为将任意一组参数传递给'spwan'包装函数。

2 个答案:

答案 0 :(得分:1)

您已经有了命令列表,现在创建一个执行单个命令的函数,并将其映射到您的池中:

def cmd_executor(cmd):
  pid = subprocess.Popen(cmd)
  pid.wait()

pool = Pool(2)
results_list = pool.map(cmd_executor, cmd_list)

这会将您的列表成员一次映射到该函数,

如果您不想使用100个进程(假设,我现在知道现在限制为2个),则可以将multiproc导入更改为使用from multiprocessing.dummy import Pool-使用线程而不是进程,这样可能会更有效,因为subprocess负责实际产生新进程。

答案 1 :(得分:0)

好,这就是我最终解决的问题,它解决了我的紧迫问题,我想足够通用,我可以灵活运用一些前进的方向:

const arr = [{ prop: 3 }, { prop: 4 }];

const pointer = new Proxy([], {
  get(target, prop, receiver) {
    // if the prop is a string that can be converted to a number
    // return the corresponding value from the arr
    if(typeof prop === 'string' && !isNaN(Number(prop))) return arr[target[prop]];

    return Reflect.get(target, prop, receiver);
  }
});

pointer.push(0, 1);
console.log(pointer);

arr.splice(0, 0, { prop: 1 });
console.log(pointer);

对我来说,诀窍是最终理解import subprocess from multiprocessing.dummy import Pool from functools import partial def spawn(cmd, **kwargs): pid = subprocess.Popen(cmd, **kwargs) pid.wait() pool = Pool(3) cmd_list=[] for x in range(5): cmd_list.append(['echo',str(x)]) # run without any kwargs, so just the basic Popen call... pool.map(spawn, cmd_list) # now add some arguments to the Popen call kwargs={} kwargs['stderr'] = subprocess.STDOUT kwargs['startupinfo'] = None # and now call it with those kwargs, using 'partial'... pool.map( partial(spawn, **kwargs) ,cmd_list) is its own special operator,并且除了“表示未打包的关键字参数列表”这一非常特定的目的外,没有任何轴承。我认为它是字符串,列表甚至是字典是错误的(尽管您使用字典来构建基本kwarg)-它仅用于解压缩参数。我敢肯定,对于使用它的人来说,这是显而易见的,但是对我而言,直到我理解了这个概念之后,整个事情才变得有意义。如丹尼尔(Danielle)上面显示的,对**kwargs的调用使我可以正确保留partial(spawn, **kwargs)的签名。