最終目標是在後臺執行一個方法,但不是並行執行:當多個對象調用這個方法時,每個方法都應該等待輪到他們進行。要實現在後臺運行,我必須在子進程(而不是線程)中運行該方法,並且需要使用spawn(而不是fork)來啓動它。爲了防止並行執行,顯而易見的解決方案是在進程之間共享全局鎖。
當分叉進程(這是Unix上的默認進程)時,很容易實現,如以下兩個代碼中突出顯示的那樣。
我們可以分享它作爲一個類變量:Python:在產生的進程之間共享一個鎖
import multiprocessing as mp
from time import sleep
class OneAtATime:
l = mp.Lock()
def f(self):
with self.l:
sleep(1)
print("Hello")
if __name__ == "__main__":
a = OneAtATime()
b = OneAtATime()
p1 = mp.Process(target = a.f)
p2 = mp.Process(target = b.f)
p1.start()
p2.start()
或者我們可以把它傳遞給方法:
import multiprocessing as mp
from time import sleep
class OneAtATime:
def f(self, l):
with l:
sleep(1)
print("Hello")
if __name__ == "__main__":
a = OneAtATime()
b = OneAtATime()
m = mp.Manager()
l = mp.Lock()
p1 = mp.Process(target = a.f, args = (l,))
p2 = mp.Process(target = b.f, args = (l,))
p1.start()
p2.start()
這兩個代碼具有打印「你好」的適當的行爲以一秒的間隔。 但是,將start method更改爲「產卵」時,它們會斷開。
第一個(1)同時打印「hello」。這是因爲the internal state of a class is not pickled,所以他們沒有相同的鎖。
第二個(2)在運行時出現FileNotFoundError失敗。我認爲這與鎖不能被醃製的事實有關:請參閱Python sharing a lock between processes。
在這個答案中,建議了兩個修正(附註:我不能使用一個池,因爲我想隨機創建任意數量的進程)。
我還沒有找到一種方法,以適應第二修復,但我試圖執行的第一個:
import multiprocessing as mp
from time import sleep
if __name__ == "__main__":
mp.set_start_method('spawn')
class OneAtATime:
def f(self, l):
with l:
sleep(1)
print("Hello")
if __name__ == "__main__":
a = OneAtATime()
b = OneAtATime()
m = mp.Manager()
l = m.Lock()
p1 = mp.Process(target = a.f, args = (l,))
p2 = mp.Process(target = b.f, args = (l,))
p1.start()
p2.start()
這種失敗,AttributeError的和FileNotFoundError(3)。事實上,當使用fork方法時,它也會失敗(BrokenPipe)(4)。
共享生成的進程之間鎖定的正確方法是什麼?
這四個失敗的快速解釋我編號也會很好。 我在Archlinux下運行Python 3.6。
聽起來你已經仔細閱讀了文檔。您是否查看了[17.2.1.5](https://docs.python.org/3.6/library/multiprocessing.html#sharing-state-between-processes)中的解決方案?你應該能夠將鎖放入共享內存或管理器中,對嗎? –
我試過了,它在第三個代碼片段中。它沒有工作,但可能有很多方法可以做到這一點,其中包括一個可以實現這一點的方法。 – Zil0
對不起,我應該在評論之前進一步研究代碼。 :-) –