打印功能使多处理程序失败

时间:2016-09-22 05:07:11

标签: python python-3.x python-multithreading python-multiprocessing

在下面的代码中,我正在尝试创建一个沙盒主工作系统,其中对worker中全局变量的更改不会反映给其他worker。

为实现这一目标,每次创建任务时都会创建一个新流程,为了使执行并行,流程本身的创建由ThreadPoolExecutor管理。

import time
from concurrent.futures import ThreadPoolExecutor
from multiprocessing import Pipe, Process


def task(conn, arg):
  conn.send(arg * 2)


def isolate_fn(fn, arg):

  def wrapped():
    parent_conn, child_conn = Pipe()
    p = Process(target=fn, args=(child_conn, arg), daemon=True)
    try:
      p.start()
      r = parent_conn.recv()
    finally:
      p.join()
    return r

  return wrapped


def main():
  with ThreadPoolExecutor(max_workers=4) as executor:
    pair = []

    for i in range(0, 10):
      pair.append((i, executor.submit(isolate_fn(task, i))))

      # This function makes the program broken.
      # 
      print('foo')

    time.sleep(2)

    for arg, future in pair:
      if future.done():
        print('arg: {}, res: {}'.format(arg, future.result()))
      else:
        print('not finished: {}'.format(arg))

  print('finished')

main()

这个程序工作正常,直到我把print('foo')函数放在循环中。如果该函数存在,则某些任务仍未完成,更糟糕的是,该程序本身无法完成。

结果并不总是相同,但以下是典型的输出:

foo
foo
foo
foo
foo
foo
foo
foo
foo
foo
arg: 0, res: 0
arg: 1, res: 2
arg: 2, res: 4
not finished: 3
not finished: 4
not finished: 5
not finished: 6
not finished: 7
not finished: 8
not finished: 9

为什么这个程序如此脆弱?

我使用Python 3.4.5。

2 个答案:

答案 0 :(得分:1)

尝试使用

from multiprocessing import set_start_method

... rest of your code here ....

if __name__ == '__main__':
    set_start_method('spawn')
    main()

如果您在Stackoverflow中搜索python多处理和多线程,您会发现一些提及类似悬挂问题的公平问题。 (尤其是对于python版本2.7和3.2)

混合多线程和多处理仍然是一个问题,甚至multiprocessing.set_start_method的python文档也提到了这一点。在你的情况下,'spawn''forkserver'应该没有任何问题。

另一种选择可能是直接使用MultiProcessingPool,但在更复杂的用例中,这可能是不可能的。

顺便说一下。 'Not Finished'可能仍会出现在您的输出中,因为您不是在等待子流程完成,但整个代码不应再挂起并且总是干净利落。

答案 1 :(得分:0)

您不是每次都创建ThreadPoolExecutor,而是每次迭代都使用预初始化池。我真的无法追踪哪个印刷声明阻碍了你?