我正在使用Python(2.7)和pymongo(3.3),我需要生成子进程来异步运行作业。不幸的是pymongo不像here所描述的那样是叉安全的(我需要在生成子进程之前与db进行交互)。
我使用shell
(True
设置为False
然后multiprocessing.Process
)和multiprocessing.Process
进行了实验。据我所知,他们都分叉父进程来创建子进程,但只有os.system
导致pymongo打印它已检测到分叉进程的警告。
我想知道这样做的pythonic方式是什么。似乎subprocess
可能会为我做,但os.system
被描述为$scope.getAtributte = function (item) {
console.log(angular.element(item).attr('validacion'));
};
的预期替代品,所以我想知道我是否遗漏了某些东西。
答案 0 :(得分:5)
不是fork安全并不意味着你不能调用fork ...它只是意味着子进程不应该使用任何继承的PyMongo实例。当您使用struct
时,新分叉的子项几乎立即调用class
替换为shell实例(shell = True)或所需的可执行文件(shell = False)。因此从PyMongo的角度来看是安全的。
相反,当您调用multiprocessing.Process时,子项确实是父项的副本,并保留其PyMongo实例。因此,在该上下文中使用PyMongo是不安全的,并且正确发出了警告消息
答案 1 :(得分:4)
我认为你误解了;因为PyMongo的文档警告你单个MongoClient不是分叉安全的,所以你认为这意味着PyMongo禁止你的整个程序创建子进程。
任何一个MongoClient都不是fork-safe,这意味着你不能在分叉之前创建它并在分叉后使用相同的MongoClient对象。在整个程序中使用PyMongo,或者在fork之前使用一个MongoClient,之后使用另一个MongoClient,都是安全的。
这就是为什么subprocess.Popen
没问题:你是fork,然后是exec(用子进程中的另一个替换你的程序),因此你不可能在之后的孩子中使用相同的MongoClient
引用PyMongo FAQ:
在Unix系统上,多处理模块使用fork()生成进程。使用带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()
永远不要这样做:
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(),线程和锁之间固有的不兼容性,从父进程复制的MongoClient实例在子进程中具有很高的死锁概率。如果有可能发生此死锁,PyMongo将尝试发出警告。
答案 2 :(得分:3)
如果您可以转到Python 3.4或更高版本,则可以在使用pymongo
之前将documentation设置为'forkserver'
。这会立即分叉服务器进程,并且将来使用multiprocessing
分叉服务器,而不是主进程。因此,一旦设置了fork服务器,您的主进程就可以使用pymongo
,fork服务器将不会使用它,因此它不会重新发生问题。
可悲的是,启动方法仅在3.4中添加,因此它不是2.7的选项,但如果其他人遇到此问题,则可能对他们有用。