在Python中从线程调用多处理安全吗?

在Python中从线程调用多处理安全吗?,第1张

在Python中从线程调用多处理安全吗?

听起来好像当前线程派生时,该进程中所有锁的状态都已复制到子进程中(这似乎是设计错误,并且肯定会死锁)。

这不是设计错误,而是

fork()
早于单进程多线程。所有锁的状态都被复制到子进程中,因为它们只是内存中的对象。进程的整个地址空间都按fork复制。仅有一些不好的选择:要么通过fork复制
所有 线程,要么拒绝多线程应用程序中的派生。

因此,

fork()
除非在子进程之后
execve()
exit()
在子进程中进行 *** 作,否则永远都不是安全的事情。

是否可以在各处用multiprocessing.Lock替换threading.Lock来避免此问题,并允许我们安全地组合线程和fork?

否。 没有什么可以安全地组合线程和派生的,这是无法做到的。


问题是,当一个进程中有多个线程时,在

fork()
系统调用之后,您将无法继续在POSIX系统中安全地运行该程序。

例如,Linux手册

fork(2)

*在

fork(2)
进入多线程程序之后,子级只能安全地调用异步信号安全函数(请参阅参考资料
signal(7)
),直到它调用为止
execve(2)

也就是说,可以

fork()
在多线程程序中然后仅调用异步信号安全的 C 函数(这是 C
函数的相当有限的子集),直到子进程已被另一个可执行文件替换!

子进程中的不安全C函数调用例如

  • malloc
    用于动态内存分配
  • <stdio.h>
    格式化输入的任何功能
  • pthread_*
    线程状态处理所需的大多数功能,包括创建新线程…

因此,子进程实际上可以安全地执行的 *** 作很少。不幸的是,CPython核心开发人员一直低估了由此引起的问题。甚至现在文档说:

请注意,安全地分叉多线程进程是 有问题的

委婉的说法是“不可能”。


如果您 使用start方法,则可以安全地 具有多个控制线程的Python进程中使用多重处理。在Python
3.4+中,现在可以更改start方法。在包括所有Python
2在内的早期Python版本中,POSIX系统始终表现为被指定为启动方法。这将导致不确定的行为。
__

fork
fork

问题不仅限于

threading.Lock
对象,还包括C标准库,C扩展等持有的 所有 锁。更糟糕的是,大多数时候人们会说“它对 我有用
…直到它停止工作。

甚至在某些情况下,看似单线程的Python程序实际上在MacOS X中是多线程的,在使用多处理时会导致失败和死锁。

另一个问题是,所有打开的文件句柄,它们的使用,共享套接字在派生的程序中可能表现得很奇怪,但是即使在单线程程序中也是如此。

TL; DR:

multiprocessing
在多线程程序中使用,带有C扩展名,打开的套接字等:

  • 如果您明确指定不是的启动方法,则在3.4+和POSIX中可以使用
    fork
  • 在Windows中很好,因为它不支持分支;
  • 在POSIX上的Python 2-3.3中:您几乎会用脚射击。


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5663932.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-16

发表评论

登录后才能评论

评论列表(0条)

保存