我正在运行许多子过程(比我有更多的核心),如果符合某个条件,我设置了全局变量的值 global bailout
。
然后,如果设置了bailout
,则所有随后的子过程尽快退出。
参见例如这个简单的示例,其中我将20个调用的结果乘以loop()
函数,但是如果这些调用中的任何一个返回零:
import sys
import random
import multiprocessing
def loop(tup):
global bailout
if bailout==1: # obey a global bail out "flag"
return 0
x = random.random() - 0.5
if x < 0:
bailout = 1 # set a global bail out "flag"
return 0
return x
def top():
global bailout
bailout = 0
runtups = 20 * [[0]] # a dummy parameter [0] for function "loop"
pool = multiprocessing.Pool()
results = pool.imap(loop, runtups)
pool.close()
res = 1
sys.stdout.write("1")
for result in results:
sys.stdout.write(" * %g" % result)
res = res * result
sys.stdout.write(" = %gn" % res)
top()
它可以正常工作(或确切地说,每次尝试使用时,它都可以使用)。即,我的桌面有4个内核,如果前4个子过程之一将救助设置为1(在此示例中几乎总是发生),则所有后续运行均在 if bailout==1
条件上退出。
但是安全吗?
我的意思是,子进程都可以做的就是将bailout
设置为1。但是,如果两个子过程都想将救助设置为1,该怎么办?他们是否有可能同时尝试,从而导致救助变得不确定?还是保证这将永远不会发生(也许是因为最高级别的过程总是在串行上处理完整的子过程?)
在过程之间未共享全球。如果您在loop
中添加一些日志记录,则可以看到真正发生的事情:
def loop(tup):
global bailout
if bailout==1:
print(f'pid {os.getpid()} had bailout 1')
return 0
x = random.random() - 0.5
if x < 0:
print(f'pid {os.getpid()} setting bailout 1')
bailout = 1
return 0
return x
这将产生类似:
的输出pid 30011 setting bailout 1
pid 30013 setting bailout 1
pid 30015 setting bailout 1
pid 30009 setting bailout 1
pid 30010 setting bailout 1
pid 30011 had bailout 1
pid 30013 had bailout 1
pid 30009 had bailout 1
pid 30014 setting bailout 1
pid 30015 had bailout 1
pid 30010 had bailout 1
pid 30011 had bailout 1
1 * 0.494123 * 0.0704172 * 0 * 0.10829 * 0 * 0.465238 * 0 * 0.0638724 * 0 * 0 * 0 * 0.227231 * 0 * 0 * 0 * 0 * 0 * 0 * 0.463628 * 0.372984 = 0
发生的事情是multiprocessing.Pool()
正在启动4个过程,这些过程被重新使用,它们可以使用。因此,在处理runtups
中的20个项目时,最终每个过程都将其bailout
设置为1。当重复使用该过程时,它会触发Bailout子句。
由于您是随机决定何时设置bailout = 1
,因此在处理20个项目时,它可能永远不会发生,或者可能在某些过程中而不是其他过程中发生,因此您可能不会得到我粘贴的相同结果,但是至少某些过程可能会进入救助模式。
如果您正在寻找一种在过程之间共享状态的可靠方法,请访问https://docs.python.org/3/library/multiprocessing.html#sharing-sharing-state-bet-bet-processes.
可能吗?
它安全吗?
是否保证?
虽然Gil-Stepping确实确实使所有基于线程的(不是基于子流程)的多处理工作仍然在纯[SERIAL]
处理中出现,但问题更多地是关于主要方法,以及上述所有提出的问题是否存在安全满足。
不要试图违反有记录的建议:
最好地提及文档中的明确语句:
16.6.3。编程指南
...
明确将资源传递给子进程
在UNIX上,儿童过程可以利用使用全局资源在父过程中创建的共享资源。但是,最好将对象作为参数传递给子女过程的构造函数。
除了将代码(潜在)与Windows兼容之外,这还可以确保,只要子进程仍然活着,对象就不会在父进程中收集垃圾。如果对象在父过程中收集垃圾时释放某些资源,这可能很重要。
和
16.6.3.2 Windows
...
全局变量
请记住,如果代码在子进程中运行以访问全局变量,那么它看到的值(如果有)可能与
Process.start
时父进程中的值不一样被称为。但是,仅是模块级常数的全局变量不会引起任何问题。
除了帮助交流或quot的本地Pythonic工具外状态(不仅我在可能的情况下提倡永远不要共享),还有一些智能工具,用于设计确实使用的分布式系统,使用多代理概念,每个线程都可以使用其他轻巧的通信工具,绩效较少,而不是本机Gil-Steppped操作允许(参考Zeromq,Nanomsg等)。