我知道在Python中,线程使用同一个Python解释器实例。我的问题是,在使用os.fork
创建进程时,是否也一样?或者每个由os.fork
创建的进程都有自己的解释器?
我知道在Python中,线程使用同一个Python解释器实例。我的问题是,在使用os.fork
创建进程时,是否也一样?或者每个由os.fork
创建的进程都有自己的解释器?
这样就会创建一个新的副本的Python解释器。
两个Python解释器同时运行的一个优点是它们现在具有两个GIL(全局解释器锁),因此可以在多核系统上实现真正的多处理。
同一进程中的线程共享相同的GIL,意味着一次只能运行一个线程,只能给出并行的错觉。
fork
确实会创建当前Python解释器的副本而不是在相同的解释器中运行,但通常这并不是您想要的,至少它不能单独使用。它存在以下问题:
fork
,那就不是真的了。最著名的是,如果让ssl
在主进程中种子PRNG,然后再fork
,那么您现在可能会得到可预测的随机数,这是安全漏洞。fork
和exec
之间实现一组非常具体的系统调用。如果您从未调用过exec
,则只能使用这些系统调用。这基本上意味着您无法在不同平台上做任何事情。fork
之后都变得非常麻烦和不可移植。有关这些问题的详细信息,请参见POSIX fork
或您所用平台的手册。
正确的答案几乎总是使用multiprocessing
,或者使用concurrent.futures
(它包装了multiprocessing
)或类似的第三方库。
从3.4版本开始,你甚至可以指定一个启动方法。使用fork
方法基本上只是调用了fork
。而使用forkserver
方法则会运行一个单一的“干净”的进程(没有线程、信号处理程序、SSL初始化等),并从该进程派生新的子进程。使用spawn
方法会调用fork
然后exec
,或者类似于posix_spawn
的等效方法,以获取全新的解释器而不是副本。因此,你可以先用fork
开始,但如果遇到任何问题,切换到forkserver
或spawn
,而无需更改代码中的其他内容。这相当不错。
os.fork()
相当于许多UNIX系统中的fork()
系统调用。因此,是的,您的子进程将与父进程分开,并具有不同的解释器(因此)。
FORK(2)
NAME fork - create a child process
SYNOPSIS #include
pid_t fork(void);
DESCRIPTION fork() creates a new process by duplicating the calling process. The new process, referred to as the child, is an exact duplicate of the calling process, referred to as the parent, except for the following points:
os.fork()
派生一个子进程。在父进程中返回子进程的pid,在子进程中返回0。如果发生错误,则引发OSError。请注意,使用fork()从线程时,包括FreeBSD <= 6.3,Cygwin和OS / 2 EMX在内的某些平台存在已知问题。
另请参阅:Martin Konecny的有关“分叉”的原因和优势的回复 :)
为简洁起见; 其他涉及不涉及单独进程和因此单独的Python解释器的并发方法包括:
yield from
asyncio
实际上使用 yield-from
协程(尽管在 3.5 中,它可能会改用新的 async
/await
协程)。值得一提的是,像 Twisted 这样更明确的回调驱动/未来驱动设计,以及直接循环遍历 selector
或 select
的等效设计。或者使用 GUI 风格的事件循环。但我已经给你点了一个赞,所以你可能不会因为添加所有这些内容而获得额外的投票。 :) - abarnert
multiprocessing.Lock
存在的事实中,你应该明白你应该使用它而不是threading.Lock
。 - abarnert