【问题标题】:Is ok to not "join" with multiprocessing, when tasks are expected to run forever?当任务预计永远运行时,可以不“加入”多处理吗?
【发布时间】:2021-06-17 20:59:26
【问题描述】:

我试图了解多处理在 python 中的工作原理,我遇到了一个用例,我想从队列系统中读取一些消息并将它们写入数据库。

在最终循环中不使用p.join() 可以吗?这是因为当我省略这个连接时,我看到的速度要快得多; 或者它的后果是什么?

我没有更多的代码。

def process():
    while True:
       message = read_from_queue()
       write_to_database(message)


for _ in range(4):
    p = Process(target=process)
    p.start()

【问题讨论】:

  • join() 是您真正等待结果返回的时间。如果您不调用它,您的程序可能会在所有工作实际完成之前退出。
  • 你应该在你执行start的循环之后join(在一个单独的循环中),而不是在它里面。将 Process 实例附加到列表中,以便您可以再次循环,执行 join
  • 问题是,有一个永远不会结束的 While 循环,因此外部连接永远不会发生
  • 如果不调用join,操作系统会继续跟踪进程。如果您经常这样做,那么您有可能会耗尽流程资源。当您的父程序退出时,它会调用join。如果您的子进程永远持续下去,则父进程也不会完全退出。您可以设置Process.daemon 标志,但在这种情况下,您的父进程将在退出时终止子进程。
  • 我觉得你现在做的还可以。您启动 4 个进程,当您的顶级脚本退出时,它会在后台加入。这里似乎缺少的是对这些子进程的管理——它们是如何终止的? - 但由于这是一个简单的例子,我也不希望有额外的细节。

标签: python multiprocessing python-multiprocessing


【解决方案1】:

Python 在使用 atexit 模块关闭之前尝试 join 所有非守护程序子进程(守护程序是 terminate()ed)。如果孩子永远奔跑,那么父母也会永远奔跑。如果父母什么都不做,只是在等待join,它不会消耗太多的系统资源,所以没什么大不了的。当您必须关闭系统/程序时,问题就出现了。 IMAO 最好为您的程序提供平滑关闭机制,使用signal.signal 设置处理程序或主进程中的某种信号量以实现平滑关闭是一个好主意。综上所述,如果您知道您的数据库访问对中断写入具有弹性(例如通过日记),您可能会选择坚持使用更简单的代码,并且不加任何优雅地杀死 python。所有现代操作系统都将在终止进程后做好清理工作。

至于速度,听起来您之前的代码可能看起来有点像这样?

for _ in range(4):
    p = Process(target=process)
    p.start()
    p.join() # <- putting join next to start is usually an anti-pattern because it basically precludes parallel-processing.

这意味着您实际上不会有 4 个子进程在运行,因为它会等待第一个子进程完成后再创建或启动(这永远不会发生,因为它永远运行)。通过将其取出,您可以在启动所有 4 个子进程后留下 joining(您可以将其留给自动加入,或在另一个循环中自行执行)。

【讨论】:

  • 您好,谢谢您的回答,加入就是这样,另一个循环将所有进程附加到列表中,但是由于“进程”循环永远不会结束,因此永远不会到达该循环。抱歉问一下,signal.signal 上是否有任何可以理解的资源?听起来是个好主意,但找不到好的解释。谢谢!
  • 他们都从更“生产代码”的角度谈论事情。我来自研究背景,并且更经常地采取以下立场:“足够好就是足够好”我几乎没有花太多时间让我的代码防弹,因为我可能是唯一一个会运行它的人。仍然......他们对如何稳健地进行多处理有很好的想法。
猜你喜欢
  • 1970-01-01
  • 2012-07-28
  • 1970-01-01
  • 1970-01-01
  • 2017-12-30
  • 1970-01-01
  • 2022-10-12
  • 2013-02-12
  • 2015-08-14
相关资源
最近更新 更多