Python 中使用多進程編程的“三兩”問題

文章目錄

  • 一、簡介
  • 二、選擇合適的啟動方式
  • 三、手動終止所有的進程
  • 小結

一、簡介

這里簡單介紹在Python中使用多進程編程的時候容易遇到的情況和解決辦法,有助于排查和規避某類問題,但是具體問題還是需要具體分析,后續會補充更多的內容。

二、選擇合適的啟動方式

  1. Python多進程編程非常需要注意啟動方式,有些庫會在fork模式下出現很詭異的阻塞或顯存泄漏。如果需要跨平臺使用,優先選擇spawn方式,如果涉及到 GPU、PyTorch、OpenCV 視頻流、TensorRT、OpenVINO ,同樣優先選擇spawn方式,避免繼承GPU上下文。有的時候會存在 多線程多進程 混用的情況,可以選擇spawnforkserver這兩種方式。 spawn啟動方式通常更安全、更穩定。

    啟動方式平臺默認機制優點缺點適用場景
    forkLinux / macOS子進程直接復制父進程的內存空間(寫時復制),從 fork() 返回處繼續執行創建速度快,占用內存少繼承父進程線程狀態可能死鎖,繼承 GPU/文件句柄可能出錯,不支持 Windows純計算、多進程間狀態共享簡單、無 GPU/大文件句柄的場景
    spawnWindows啟動全新的 Python 解釋器進程,從頭執行 __main__ 模塊的代碼跨平臺一致,狀態干凈,不繼承父進程線程/句柄/GPU context啟動慢,初始化開銷大,需要 if __name__ == "__main__":GPU 深度學習、跨平臺項目、多線程+多進程混合、需要隔離狀態的場景
    forkserverLinux / macOS先啟動一個 “fork server” 進程,之后所有子進程由它 fork 出來避免從主進程直接 fork(減少死鎖風險),比 spawn 快只在類 Unix 系統可用,需額外啟動 server,復雜度高多線程+多進程并存、需要避免主進程 fork 的高并發服務
  2. 可以通過調用multiprocessing.set_start_method('spawn')來指定子進程的啟動方式,通常寫在if __name__ == "__main__":里,force=True參數可以強制重置啟動方式(但通常不建議隨便用,除非確定沒別的進程創建了子進程)。

    import multiprocessing as mpdef worker(name):print(f"Worker {name} running...")if __name__ == "__main__":# 強制統一 spawnmp.set_start_method("spawn", force=True)  # "fork" 或 "forkserver" processes = []for i in range(3):p = mp.Process(target=worker, args=(i,))p.start()processes.append(p)for p in processes:p.join()
    
  3. 使用 PyAV 調用h264_qsv(Intel Quick Sync Video)硬件加速解碼時,也會受多進程啟動方式的影響,QSV 是基于英特爾硬件加速的編碼解碼技術,需要在進程中正確初始化硬件上下文。如果使用fork,子進程會復制父進程的內存空間,但硬件設備上下文(如 QSV 的硬件句柄、驅動狀態等)通常不能被正確繼承或共享,導致解碼失敗、死鎖或崩潰。使用spawn,子進程是全新啟動,獨立初始化硬件上下文,能避免因上下文繼承帶來的問題,提高穩定性。

    多進程啟動方式對 PyAV + h264_qsv 硬解碼的影響推薦做法
    fork可能導致硬件上下文沖突,解碼異常不推薦
    spawn子進程獨立初始化硬件上下文,穩定性高推薦,尤其多進程并發的時候
  4. 在使用fork啟動多進程的時候,部分常用的 計算機視覺 (CV)和 點云處理 相關庫可能會出現問題,任何涉及 GPU上下文、線程池或多線程加速的庫,在fork多進程啟動方式下都可能出現資源繼承異常、死鎖、崩潰等問題。點云庫中,Open3DPCL 較為復雜,fork時要特別注意。

    庫/模塊說明與常見問題
    OpenCV (cv2)GPU模式(CUDA)在fork后可能資源異常或崩潰,多線程環境下死鎖;CPU模式一般安全,但多線程仍需注意。
    Open3D內部使用線程池和GPU(部分功能),fork啟動時可能導致線程池狀態異常或GPU資源不可用。
    PCL / python-pcl底層多線程和GPU支持(部分平臺),fork后可能出現線程死鎖或資源沖突,尤其在GPU加速時。
    PyTorchfork后CUDA上下文繼承出錯,導致報錯、卡死;多線程資源也可能異常。
    TensorFlowfork后session、資源無法正常初始化,多線程管理導致崩潰。
    OpenVINO線程池和設備初始化受fork影響,可能導致設備資源沖突或初始化失敗。
    TensorRTGPU上下文和優化緩存fork后不穩定,可能導致初始化失敗或運行錯誤。
    matplotlibGUI線程在fork后可能卡死或異常。

三、手動終止所有的進程

  1. 多進程中 Ctrl+CSIGINT 信號)后程序沒有全部退出,最常見原因就是信號沒有傳遞給子進程,或者子進程沒能響應退出請求。fork導致資源繼承異常也經常是根源。列出當前系統中所有正在運行的 Python 進程及其詳細信息。

    ps aux | grep python
    
  2. 在多進程場景下,torch.utils.data.DataLoader是常見的導致進程無法退出的元兇之一,尤其是在num_workers > 0時。有的情況默認不監聽結束信號,有的情況收不到結束信號。顯式處理可能比較麻煩。

  3. 一個比較安全的寫法是在主進程捕獲SIGINT,然后主動殺掉自己啟動的所有子進程。直接一次性結束整個進程樹。

    import multiprocessing as mp
    import signal
    import sys
    import os
    import psutildef kill_all_children(timeout=3):"""終止當前進程的所有子進程(遞歸),先嘗試終止,再強制殺死超時未結束的子進程"""proc = psutil.Process(os.getpid())children = proc.children(recursive=True)# 嘗試終止for child in children:try:child.terminate()except Exception as e:print(f"[警告] 無法終止 PID={child.pid}: {e}", file=sys.stderr)# 等待超時,獲取仍然存活的子進程gone, alive = psutil.wait_procs(children, timeout=timeout)# 強制殺死仍然存活的進程for child in alive:try:child.kill()except Exception as e:print(f"[錯誤] 無法強制終止 PID={child.pid}: {e}", file=sys.stderr)def signal_handler(sig, frame):   # 回調函數print(f"\n[退出] 捕獲信號 {sig},終止子進程并退出...")try:kill_all_children()except Exception as e:print(f"[錯誤] 終止子進程時出錯: {e}", file=sys.stderr)finally:sys.exit(130 if sig == signal.SIGINT else 143)  # 130 = Ctrl+C 退出, 143 = SIGTERM 退出def main(args):# 啟動多個進程的示例processes = []for _ in range(4):p = mp.Process(target=worker_function)p.start()processes.append(p)for p in processes:p.join()if __name__ == "__main__":signal.signal(signal.SIGINT, signal_handler)   # 注冊信號和回調函數signal.signal(signal.SIGTERM, signal_handler)mp.set_start_method('spawn', force=True)args = parse_args()main(args)
    
  4. 或者更簡單直接的立即殺掉所有進程,終端更干凈。可以根據實際情況考慮如何使用。

    import multiprocessing as mp
    import signal
    import sys
    import os
    import psutildef kill_all_processes():proc = psutil.Process(os.getpid())for child in proc.children(recursive=True):child.kill()proc.kill()def signal_handler(sig, frame):print("\n[退出] 捕獲 Ctrl+C,終止所有進程...")kill_all_processes()sys.exit(0)def main(args):# 啟動多個進程的示例processes = []for _ in range(4):p = mp.Process(target=worker_function)p.start()processes.append(p)for p in processes:p.join()if __name__ == "__main__":signal.signal(signal.SIGINT, signal_handler)signal.signal(signal.SIGTERM, signal_handler)mp.set_start_method('spawn', force=True)args = parse_args()main(args)
    

小結

以上內容來自相關資料和個人實踐,具體情況還請具體分析,可以參考這里提到的幾個關鍵點,有助于排查問題,如有問題歡迎在評論區指正,謝謝!!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/92887.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/92887.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/92887.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Ansible部署應用

目錄Ansible概述1:什么是Ansible2:Ansible的架構組成3:Ansible與SaltStack的對比安裝部署Ansible服務1:系統環境設置2:安裝Ansible(第一臺)2:配置主機清單3:修改Ansible配…

疏老師-python訓練營-Day44預訓練模型

浙大疏錦行 知識點回顧: 預訓練的概念常見的分類預訓練模型圖像預訓練模型的發展史預訓練的策略預訓練代碼實戰:resnet18 作業: 嘗試在cifar10對比如下其他的預訓練模型,觀察差異,盡可能和他人選擇的不同嘗試通過ctrl進…

AI入門學習--如何寫好prompt?

寫好Prompt(提示詞)是駕馭AI模型的核心技能。以下是結合測試工程師需求的 結構化方法論 和 黃金模板一、prompt設計金字塔終極心法: Prompt 對AI的測試需求文檔,需像設計測試用例一樣:可執行:明確輸入輸出…

Linux編程 IO(標準io,文件io,目錄io)

標準IO C語言標準IO概述標準IO&#xff08;Standard Input/Output&#xff09;是C語言中用于處理文件和數據流的一組函數庫&#xff0c;定義在<stdio.h>頭文件中。與低級IO&#xff08;如read/write&#xff09;相比&#xff0c;標準IO提供了緩沖機制&#xff0c;提高了數…

C# WPF本地Deepseek部署

模型下載地址 using LLama; using LLama.Common; using System; using System.IO; using System.Threading.Tasks; using System.Windows; using System.Windows.Input;namespace YF_Talk {public partial class MainWindow : Window{private LLamaWeights _model;private LLa…

【Abp.VNext】Abp.Vnext框架模塊學習

1、Abp.Vnext-集成 Volo.Abp.Core2、Abp.vNext-Web模塊 Volo.Abp.AspNetCore.MVC框架&#xff08;framework文件夾&#xff09; 七、Abp.vNext-應用模塊-Identity身份認證 業務模塊&#xff08;modules文件夾->identity&#xff09; 1、添加領域模型 Volo.Abp.Identity.Doma…

【完整源碼+數據集+部署教程】火柴實例分割系統源碼和數據集:改進yolo11-rmt

背景意義 研究背景與意義 在計算機視覺領域&#xff0c;實例分割技術作為一種重要的圖像處理方法&#xff0c;近年來得到了廣泛的關注和應用。實例分割不僅能夠識別圖像中的物體類別&#xff0c;還能精確地分割出每個物體的輪廓&#xff0c;提供更為細致的視覺信息。這一技術在…

飛算JavaAI云原生實踐:基于Docker與K8s的自動化部署架構解析

一、飛算JavaAI詳細介紹 1.1 飛算JavaAI飛算JavaAI是飛算云智推出的一款革命性Java開發輔助工具&#xff0c;它通過人工智能技術深度賦能傳統軟件開發流程&#xff0c;特別為大學生課程設計、畢業設計等實踐教學環節提供了強有力的技術支持。在當前高校計算機相關專業教學中&am…

小程序打通美團核銷:解鎖到店綜合業態私域密碼,賦能6000+門店破局增長

數字化浪潮奔涌而來&#xff0c;棋牌室、臺球廳、親子樂園等線下綜合業態面臨經營轉型的關鍵節點。小程序與美團核銷功能的深度耦合&#xff0c;正成為撬動私域流量的核心杠桿&#xff0c;為超6000家門店打通了一條低成本、高轉化的經營快車道。過往經營模式中&#xff0c;線上…

Linux Shell:Nano 編輯器備忘

打開文件 sudo nano /etc/apt/sources.list選中多行&#xff0c;然后刪除 用方向鍵將光標定位到要刪除的起始位置按下 Alt A 設置錨點用方向鍵選擇要刪除的區域 (以上 3 步是為了選中文本)用 Ctrl K(剪切) 或 Alt D(直接刪除) 全選并刪除 按下 Alt \ 將光標移動到文件開頭…

常見的設計模式(2)單例模式

目錄 一、版本一&#xff1a;禁用構造與拷貝 二、版本二&#xff1a;注冊析構函數/嵌套垃圾回收 &#xff08;1&#xff09;使用atexit注冊程序結束時的函數 &#xff08;2&#xff09;使用對象嵌套垃圾回收 三、版本三&#xff1a;線程安全 四、版本四&#xff1a;編譯器…

JAiRouter 0.2.1 更新啦:內存優化 + 配置合并 + IP 限流增強,運維體驗再升級

JAiRouter 0.2.1 更新啦&#xff1a;內存優化 配置合并 IP 限流增強&#xff0c;運維體驗再升級 如果你已經在 0.2.0 生產環境中穩定運行&#xff0c;那么這篇更新會讓你無痛升級&#xff0c;直接“更輕、更穩、更省心”。 &#x1f4ce; 官方倉庫 & issue 直達 https://…

學習嵌入式第二十六天

文章目錄IO(續上)1.標準IO1.標準IO的接口2.流的定位2.文件IO1.概念&#xff1a;2.系統調用和庫函數3.文件IO函數接口習題IO(續上) 1.標準IO 1.標準IO的接口 fwrite 原型&#xff1a;size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream); 功能&#xff1…

GDB 程序啟動參數設置深度指南

GDB 程序啟動參數設置深度指南 1. 概述 在程序調試過程中&#xff0c;正確設置啟動參數對于驗證程序行為、重現特定場景至關重要。GDB提供多種靈活的方式設置啟動參數&#xff0c;特別是當您需要調試命令行參數處理邏輯或配置敏感型應用時。 2. 參數設置的核心方法 2.1 啟動GDB…

Autudl華為昇騰系列NPU簡介和部署推理yolo11 yolov8 yolov5分割模型

0.配置Autudl 下面圖片是我所租的昇騰卡和具體環境版本&#xff0c;太具體的就不說了&#xff0c;有需要的話我單獨出一期Autudl租顯卡的教程&#xff0c;主要是為了學習昇騰環境如何運行Yolo系列模型。 0.1華為昇騰芯片&#xff08;Ascend&#xff09;簡介 1.Ascend 310&…

什么是JSP和Servlet以及二者的關系

JSP&#xff08;JavaServer Pages&#xff09; 是“HTML 里寫 Java”的模板技術&#xff0c;最終會被容器轉換成 Servlet。Servlet 是“Java 里寫 HTML”的 Java 類&#xff0c;直接繼承 javax.servlet.http.HttpServlet&#xff0c;用來接收/響應 HTTP 請求。Servlet 是什么 純…

【WonderTrader源碼詳解 1】【環境搭建 2】【編譯安裝WonderTrader】

一、引言 本篇來講述如何搭建 wondertrader 和 wtpy 二、wondertrader 2.1 源碼下載 # /home/leo/sda_1.6TBgit clone https://gitee.com/wondertrader/wondertrader.gitgit clone https://gitee.com/wondertrader/wtpy.git2.2 源碼編譯 cd /home/leo/sda_1.6TB/wondertrader/s…

hutool 作為http 客戶端工具調用的一點點總結

場景一&#xff1a;客戶端timeout 的時間給的很短//100毫秒 private static final int HTTP_TIMEOUT_MS 1 * 100; response HttpUtil.createPost(patrolresultconfirmUrl).body(JSONObject.toJSONString(search)).header("Authorization", token).timeout(HTTP_TI…

基于MongoDB/HBase的知識共享平臺的設計與實現

標題:基于MongoDB/HBase的知識共享平臺的設計與實現內容:1.摘要 在當今信息爆炸的時代&#xff0c;知識的有效共享和管理變得愈發重要。本研究的目的是設計并實現一個基于MongoDB/HBase的知識共享平臺&#xff0c;以滿足大規模知識數據的存儲、高效查詢和快速共享需求。方法上&…

PHP數組操作:交集、并集和差集

1. 交集&#xff08;Intersection&#xff09;交集是指兩個集合中都存在的元素。$array1 [1, 2, 3, 4]; $array2 [3, 4, 5, 6];$intersection array_intersect($array1, $array2); print_r($intersection); // 輸出: Array ( [2] > 3 [3] > 4 )2. 并集&#xff08;Uni…