1. 程式人生 > 其它 >can only join a child process

can only join a child process

上次 gevent.hub.BlockingSwitchOutError: Impossible to call blocking function in the event loop callback 這篇文章記錄的優雅退出的問題,前後還有些東西想記錄一下。

一開始遇到的問題是本地執行某個服務(宣告一下不是我寫的),ctrl+c 結束時報錯:

  File "/usr/local/lib/python3.6/multiprocessing/process.py", line 122, in join
    assert self._parent_pid == os.getpid(), 'can only join a child process'

經過調查(看程式碼查資料),發現原來是因為在啟動多程序之前註冊了訊號處理的回撥函式,並且在回撥函式最後執行了對多程序的 join。有點像這樣:

def run(self):
        ...

def start(self):
    # 註冊 SIGINT 訊號的回撥函式
    signal.signal(signal.SIGINT, self.graceful_exit)

    # 啟動一個心跳協程
    self.heartbeat_task = gevent.spawn(self.heartbeat)

    # 建立子程序
    self.workers = [multiprocessing.Process(
        target=self.run) for _ in range(4)]
    for worker in self.workers:
        worker.start()

def graceful_exit(self, sig, frame):
    ...
    # join 是等待程序結束
    for worker in self.workers:
        worker.join()

另外一點是,還在建立子程序前建立了一個 gevent 協程。而被用來的開發者忽略掉的重要問題就是:

建立子程序,也就是呼叫了作業系統的 fork,而 fork 會繼承當前程序的訊號處理回撥函式以及協程,其實就是拷貝了整個當前程序,準確點說是寫時拷貝,如果只是讀的話,那讀的都和原來程序是同一個記憶體。

明白了這一點,問題就很清晰了。


┆涼┆暖┆降┆等┆幸┆我┆我┆裡┆將┆ ┆可┆有┆謙┆戮┆那┆ ┆大┆始┆ ┆然┆
┆薄┆一┆臨┆你┆的┆還┆沒┆ ┆來┆ ┆是┆來┆遜┆沒┆些┆ ┆雁┆終┆ ┆而┆
┆ ┆暖┆ ┆如┆地┆站┆有┆ ┆也┆ ┆我┆ ┆的┆有┆精┆ ┆也┆沒┆ ┆你┆
┆ ┆這┆ ┆試┆方┆在┆逃┆ ┆會┆ ┆在┆ ┆清┆來┆準┆ ┆沒┆有┆ ┆沒┆
┆ ┆生┆ ┆探┆ ┆最┆避┆ ┆在┆ ┆這┆ ┆晨┆ ┆的┆ ┆有┆來┆ ┆有┆
┆ ┆之┆ ┆般┆ ┆不┆ ┆ ┆這┆ ┆裡┆ ┆沒┆ ┆殺┆ ┆來┆ ┆ ┆來┆