Python多進程Pipe報錯“管道已關閉”:如何優雅地處理父子進程通信中的EOFError?

Python多進程Pipe報錯“管道已關閉”:如何優雅地處理父子進程通信中的EOFError?

python多進程Pipe的“管道已關閉”錯誤及解決方案

使用Python的multiprocessing模塊中的Pipe進行父子進程通信時,可能會遇到“管道已關閉” (EOFError) 錯誤。本文分析此問題并提供解決方案。

問題描述: 子進程長期運行(例如,啟動Web服務器),主進程在子進程結束前退出,導致子進程收到“管道已關閉”錯誤,程序崩潰。

代碼分析: service.py模擬一個長期運行的子進程,通過管道接收主進程信號;single.py作為主進程,啟動子進程并接收返回信息。 問題在于主進程快速退出時,子進程阻塞在child_conn.recv(),等待主進程信號,但管道已關閉,引發錯誤。

立即學習Python免費學習筆記(深入)”;

錯誤原因: 主進程在子進程完成child_conn.recv()前退出,子進程嘗試從已關閉的管道讀取數據,導致EOFError。

解決方案: 在子進程中添加異常處理,捕獲EOFError。當主進程提前退出,子進程收到EOFError后,優雅地結束,避免程序崩潰。

改進后的代碼:

service.py:

import os from multiprocessing import Process, Pipe  def start_child_process(child_conn):     child_conn.send({"port": 123, "ret": 1, "pid": os.getpid()})     try:         signal = child_conn.recv()  # 等待主進程信號         if signal:             child_conn.close()     except EOFError as e:         print(f"Pipe closed gracefully: {e}")  # 優雅處理EOFError   class Server:     def __init__(self):         self.parent_conn, self.child_conn = Pipe()         self.child = None      def run(self):         self.child = Process(target=start_child_process, args=(self.child_conn,))         self.child.start()         data = self.parent_conn.recv()         result = {"endpoints": {"http": f"http://127.0.0.1:{data['port']}/cmd", "ws": f"ws://127.0.0.1:{data['port']}/api"}}         return result      def stop(self):         self.parent_conn.send(True)         self.child.join()         self.child = None  if __name__ == "__main__":     server = Server()     r = server.run()     print("r:", r)

single.py:

from service import Server import time  def main():     server = Server()     result = server.run()     print("r:", result)     time.sleep(5)     server.stop() # 解除注釋,測試優雅退出   if __name__ == "__main__":     main()

通過在start_child_process函數中使用try…except塊捕獲EOFError,即使主進程提前退出,子進程也能正常結束,避免了“管道已關閉”錯誤。 但這只是錯誤處理,更完善的方案可能需要考慮其他進程間通信機制或信號處理。

? 版權聲明
THE END
喜歡就支持一下吧
點贊7 分享