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

在Python中从线程调用多处理安全吗?,python,python-multiprocessing,Python,Python Multiprocessing,据 ,及 Python多处理模块不允许在线程内使用。这是真的吗 我的理解是,只要你愿意,从线中分叉是可以的 没有保留线程。执行此操作时锁定(在当前线程中?进程中的任何位置?)。然而,Python对于线程.Lock对象是否在fork之后安全地共享并不关心 还有一个问题:日志模块共享的锁会导致fork出现问题 我不知道这个问题是怎么产生的。听起来,当当前线程分叉时,进程中任何锁的状态都会复制到子进程中(这似乎是一个设计错误,肯定会死锁)。如果是这样的话,使用多处理真的提供了任何防止这种情况的保护吗(

据 ,及 Python多处理模块不允许在线程内使用。这是真的吗

我的理解是,只要你愿意,从线中分叉是可以的 没有保留线程。执行此操作时锁定(在当前线程中?进程中的任何位置?)。然而,Python对于线程.Lock对象是否在fork之后安全地共享并不关心

还有一个问题:日志模块共享的锁会导致fork出现问题

我不知道这个问题是怎么产生的。听起来,当当前线程分叉时,进程中任何锁的状态都会复制到子进程中(这似乎是一个设计错误,肯定会死锁)。如果是这样的话,使用多处理真的提供了任何防止这种情况的保护吗(因为我可以在其他线程创建和输入线程后自由创建多处理.Pool.Lock,并且在线程开始使用非fork安全日志模块之后)--多处理模块文档也对是否应在锁定前分配多处理池保持沉默

将threading.Lock替换为multiprocessing.Lock everywhere是否可以避免此问题,并允许我们安全地组合线程和分叉

听起来,当当前线程分叉时,进程中任何锁的状态都会复制到子进程中(这似乎是一个设计错误,肯定会死锁)

这不是一个设计错误,相反,
fork()
早于单进程多线程。所有锁的状态都复制到子进程中,因为它们只是内存中的对象;进程的整个地址空间将按fork中的原样复制。只有坏的选择:要么通过fork复制所有线程,要么在多线程应用程序中拒绝fork

因此,在多线程程序中执行
fork()
从来都不是一件安全的事情,除非在子进程中紧跟
execve()
exit()

将threading.Lock替换为multiprocessing.Lock everywhere是否可以避免此问题,并允许我们安全地组合线程和分叉

否。没有什么能保证螺纹和叉子的结合是安全的,这是不可能做到的


问题是,当一个进程中有多个线程时,在
fork()
system调用之后,无法在POSIX系统中继续安全地运行该程序

例如,Linux手册:

  • 在多线程程序中执行
    fork(2)
    后,子级可以安全地调用 只有异步信号安全功能(请参阅),直到 电话
也就是说,可以在多线程程序中调用
fork()
,然后只调用异步信号安全C函数(这是C函数的一个相当有限的子集),直到子进程被另一个可执行文件替换

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

  • malloc
    用于动态内存分配
  • 用于格式化输入的任何
    函数
  • 线程状态处理所需的大多数
    pthread.*
    函数,包括创建新线程
因此,子进程实际上可以安全地做的事情很少。不幸的是,CPython核心开发人员一直在淡化由此引起的问题。即使是现在,政府也说:

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

“不可能”的委婉说法


如果您不使用
fork
start方法,那么使用具有多个控制线程的Python进程的多处理是安全的;在Python3.4+中,它是。在以前的Python版本(包括所有Python 2)中,POSIX系统的行为总是好像
fork
被指定为start方法;这将导致未定义的行为

问题不仅限于
线程。锁定
对象,而是C标准库、C扩展等持有的所有锁。更糟糕的是,大多数时候人们会说“它适用于me”。。。直到它停止工作

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

另一个问题是,在分叉的程序中,所有打开的文件句柄、它们的使用、共享套接字的行为可能会异常,但即使在单线程程序中也是如此

TL;DR:在多线程程序中使用
多处理
,使用C扩展,打开套接字等:

  • 在3.4+&POSIX中,如果您明确指定的启动方法不是
    fork
    ,则可以
  • 在Windows中很好,因为它不支持分叉
  • 在POSIX上的Python2-3.3中:您将主要朝自己的脚开枪

关于
如何控制子线程的问题,如果包含另一个子线程,我的意见是不行的。我们应该更喜欢多处理。到处锁?无限循环下的无if进程!多处理是否在内部调用fork?(在这种情况下,如果我们已经创建了一个锁,我们应该关注)。@user48956这与python锁没有任何关系;问题是,如果你有一个多线程程序,你实际上无论如何都不能阻止Python代码中的不良行为。我不确定公平地说这是不可能安全的。我认为问题在于分叉是在不知道锁的情况下进行的。例如,在更好的(更高级别)框架中,您可以在fork断言或阻塞,直到没有活动锁为止。这将要求Python只依赖于fork安全且没有锁的C库,或者Python保证没有C代码在fork上执行。这是可能的,但很困难。Python可能会问操作系统--“是吗?”