我想你误会;由于PyMongo的文档警告你,单个MongoClient不是fork-safe,你可以解释为PyMongo禁止你的整个程序创建子进程。
任何单个MongoClient不是叉安全的,这意味着你不能分叉之前创建它,分叉后,使用相同的MongoClient对象。总体来说,在程序中使用PyMongo,或者在分叉之前使用一个MongoClient,而在之后使用不同的MongoClient都是安全的。
这就是为什么subprocess.Popen
没问题:你分叉,然后执行exec(用子进程中的另一个代替你的程序),因此你不可能在子进程中使用同一个MongoClient。
引述PyMongo FAQ:
在Unix系统的多处理模块使用叉产生进程()。在fork()中使用MongoClient实例时必须小心。具体来说,MongoClient的实例不能从父进程复制到子进程。相反,父进程和每个子进程必须创建他们自己的MongoClient实例。例如:
# Each process creates its own instance of MongoClient.
def func():
db = pymongo.MongoClient().mydb
# Do something with db.
proc = multiprocessing.Process(target=func)
proc.start()
永远不要这样做:MongoClient的
client = pymongo.MongoClient()
# Each child process attempts to copy a global MongoClient
# created in the parent process. Never do this.
def func():
db = client.mydb
# Do something with db.
proc = multiprocessing.Process(target=func)
proc.start()
实例从父进程复制具有僵局的子进程中的高概率,由于固有的fork(),线程和锁之间的不兼容性。如果发生这种死锁,PyMongo会尝试发出警告。
啊哈有道理,我也很好奇在子进程中继承文件描述符(特别是套接字句柄)的潜在副作用,但我猜Popen的close_fds参数地址也是 – nonagon
PyMongo使用FD_CLOEXEC创建其套接字,因此无论您是否传递close_fds,这些描述符都会关闭。 –