簡體   English   中英

在Python中生成進程而無需分叉

[英]Spawn a process in Python without forking

我正在使用Python(2.7)和pymongo(3.3),並且需要產生一個子進程來異步運行作業。 不幸的是pymongo不是這里描述的fork安全的(並且我需要在生成子進程之前與db進行交互)。

我使用subprocess.Popenshell設置為True然后為False )和multiprocessing.Process 據我所知,它們都派生了父進程來創建子進程,但是只有multiprocessing.Process導致pymongo打印警告,表明它已檢測到分叉的進程。

我想知道這樣做的pythonic方法是什么。 似乎os.system會為我做,但是subprocess os.system被描述為os.system的預期替代品,因此我想知道我是否缺少某些東西。

不是安全的分叉並不意味着您不能調用fork ...只是意味着子進程不應使用任何繼承的PyMongo實例。 當您使用subprocess.Popen ,新創建的子級幾乎立即調用exec以將其替換為shell實例(shell = True)或所需的可執行文件(shell = False)。 因此,從PyMongo的角度來看,它是安全的。

相反,當您調用multiprocessing.Process時,子級確實是父級的副本,並且確實保留了其PyMongo實例。 因此在這種情況下使用PyMongo是不安全的,並且警告消息已正確發出

我想你誤會了; 由於PyMongo的文檔警告您單個MongoClient並不安全,因此您將其解釋為PyMongo禁止整個程序創建子進程。

任何單個MongoClient都不是分叉安全的,這意味着您不能在派生之前創建它,而在派生之后不能使用相同的MongoClient對象。 整體上在程序中使用PyMongo,或者在分叉之前使用一個MongoClient,然后在分叉之后使用另一個,都是安全的。

這就是為什么subprocess.Popen可以的原因:先進行分叉,然后執行(將程序替換為子進程中的另一個程序),因此您以后可能無法在子級中使用相同的MongoClient。

引用PyMongo常見問題解答

在Unix系統上,多處理模塊使用fork()生成進程。 將MongoClient實例與fork()配合使用時必須小心。 特別是,絕不能將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將嘗試發出警告。

如果您能夠使用Python 3.4或更高版本,則可以在使用pymongo之前將multiprocessing啟動方法設置為'forkserver' 這將立即派生一個派生服務器進程,並且將來所有使用該派生服務器的multiprocessing派生,而不是您的主進程。 因此,一旦建立了fork服務器,您的主進程就可以使用pymongo ,fork服務器將不再使用它,因此不會有任何問題。

可悲的是,啟動方法僅在3.4中添加,因此它不是2.7的選項,但是如果其他人遇到此問題,則對他們可能有用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM