3
import multiprocessing as mp

def delay_one_second(event):
    print 'in SECONDARY process, preparing to wait for 1 second'
    event.wait(1)
    print 'in the SECONDARY process, preparing to raise the event'
    event.set()

if __name__=='__main__':
    evt = mp.Event()
    print 'preparing to wait 10 seconds in the PRIMARY process'
    mp.Process(target = delay_one_second, args=(evt,)).start()
    evt.wait(10)
    print 'PRIMARY process, waking up'

这段代码(在 cmd.exe 中使用“python module.py”命令在模块内部运行良好)产生了令人惊讶的结果。

主进程显然只等待 1 秒钟就醒了。为此,这意味着辅助进程引用了主进程中的对象。

怎么会这样?我原以为必须使用 multiprocessing.Manager() 在进程之间共享对象,但这怎么可能呢?

我的意思是进程不是线程,它们不应该使用相同的内存空间。有人知道这里发生了什么吗?

4

2 回答 2

2

简短的回答是共享内存不是由单独的进程管理的。它由操作系统本身管理。

如果您花一些时间浏览multiprocessing源代码,您可以了解它是如何工作的。您会看到一个Event对象使用 aSemaphore和 a Condition,这两者都依赖于SemLock对象提供的锁定行为。这反过来又包装了一个_multiprocessing.SemLock对象,该对象在 c 中实现并依赖于sem_open(POSIX) 或CreateSemaphore(Windows)。

这些是允许访问由操作系统本身管理的共享资源的 c 函数——在本例中,称为信号量。它们可以在线程进程之间共享;操作系统负责一切。发生的情况是,当一个新的信号量被创建时,它被赋予了一个句柄。然后,当创建需要访问该信号量的新进程时,它会获得句柄的副本。然后它将句柄传递给sem_openor CreateSemapohre,操作系统让新进程访问原始信号量。

所以内存共享的,但它是作为操作系统对同步原语的内置支持的一部分而共享的。换句话说,在这种情况下,您不需要打开一个新进程来管理共享内存;操作系统接管该任务。但这只是可能的,因为Event不需要比信号量更复杂的东西来工作。

于 2013-04-21T21:18:28.643 回答
2

文档说多处理模块遵循线程 API。我的猜测是它使用了类似于“fork”的机制。如果您分叉一个线程,您的操作系统将创建当前进程的副本。这意味着它复制了堆和堆栈,包括所有变量和全局变量,这就是您所看到的。

如果您将下面的函数传递给新进程,您可以自己查看它。

def print_globals():
    print globals()
于 2013-04-21T18:31:13.640 回答