os.waitpid()似乎无法正常工作

时间:2013-07-01 17:26:15

标签: python

我有三个函数(两个循环)定义,我想从command_1到command_3处理一大块文件,一旦完成,使用相同的工作流程返回处理另一个块。

伪代码显示在这里

实际代码更长并正常工作:

def run(cmd):
  try:
    subprocess.Popen(command,shell='True')
  except:
    exit()

def run_chunk(chunk,command,flag=False)
  for file in chunk
    cmd = eval(command+'("' + bam + ')"') 
    run(cmd)
def main():
  chunks = [[chunk1],[chunk2]...]
  for chunk in chunks:
    run_chunk(chunk, command_1, True)
    os.waitpid(-1,0)
    run_chunk(chunk, command_2, True)
    os.waitpid(-1,0)
    run_chunk(chunk, command_3, True)
    os.waitpid(-1,0)

注意:eval将返回一个字符串,这是“run”函数的命令

我的问题是,当我运行command_1时,os.waitpid()似乎正在运行;一旦command_1完成,程序进入command_2,在我看来command_2将在转到command_3之前等待,但main函数中的外部循环将立即执行command_1(我不想要)

有人能发现代码中的任何错误吗? 非常感谢!

2 个答案:

答案 0 :(得分:1)

通过查看API,我认为问题可能与您等待子进程的方式有关。我建议实际上尝试等待孩子的特定pid( waitpid(child1))。您可以从Popen电话中获取该信息。

  

如果pid大于0,则waitpid()请求该特定进程的状态信息。如果pid为0,则请求是针对当前进程的进程组中的任何子进程的状态。如果pid为-1,则该请求与当前进程的任何子进程有关。如果pid小于-1,则为进程组中的任何进程请求状态-pid(pid的绝对值)。

答案 1 :(得分:1)

每次调用run_chunk都可能会产生许多子子进程。 os.waitpid(-1, 0)将等待任何子子进程结束。如果chunk中有多个文件,那么os.waitpid(-1, 0)将在所有子项子进程完成之前返回。因此,对run_chunk的后续调用可能会过早发生。

如果您希望每次调用run按顺序发生,请在proc.communicate()中添加对run的调用:

def run(cmd):
    try:
        proc = subprocess.Popen(cmd, shell=True)
        proc.communicate()
    except:
        exit()

如果您希望run生成的所有run_chunk来电同时发生,那么最简单的方法就是使用multiprocessing ThreadPool

import multiprocessing.pool as mpool

def run(cmd):
    try:
        proc = subprocess.Popen(cmd, shell=True)
        proc.communicate()
    except:
        exit()

def run_chunk(chunk, command, flag=False):
    for file in chunk:
        cmd = eval(command + '("' + bam + ')"')
        pool.apply_async(run, args=(cmd,))
    pool.join()  # wait until all the calls to run have completed.

def main():
    chunks = [[chunk1], [chunk2]...]
    for chunk in chunks:
        run_chunk(chunk, command_1, True)
        run_chunk(chunk, command_2, True)
        run_chunk(chunk, command_3, True)

if __name__ == '__main__':
    pool = mpool.ThreadPool() 

我选择在这里使用ThreadPool而不是常规的多处理池,因为池中的每个工作者只调用subprocess.Popen,这反过来会产生一个新的子进程。池中的worker只是等待该子进程完成。因此,在自己的子流程中运行worker似乎是一种浪费。我认为一个重量更轻的线程就可以了。

如果在实例化mpool.ThreadPool时没有指定数字,那么您将获得一个拥有与CPU内核一样多的工作线程的池。这对我来说听起来是最理想的,因为每个工作线程都会产生一个自然需要核心的子进程。因此,有更多的工作线程(因此更多的子进程)比核心更重要,因为剩余的子进程只需要等待可用的核心。