在Python中生成一个没有分叉的进程

时间:2017-02-28 17:05:22

标签: python subprocess pymongo python-2.x python-multiprocessing

我正在使用Python(2.7)和pymongo(3.3),我需要生成子进程来异步运行作业。不幸的是pymongo不像here所描述的那样是叉安全的(我需要在生成子进程之前与db进行交互)。

我使用shellTrue设置为False然后multiprocessing.Process)和multiprocessing.Process进行了实验。据我所知,他们都分叉父进程来创建子进程,但只有os.system导致pymongo打印它已检测到分叉进程的警告。

我想知道这样做的pythonic方式是什么。似乎subprocess可能会为我做,但os.system被描述为$scope.getAtributte = function (item) { console.log(angular.element(item).attr('validacion')); }; 的预期替代品,所以我想知道我是否遗漏了某些东西。

3 个答案:

答案 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的选项,但如果其他人遇到此问题,则可能对他们有用。