多處理模組

from __future__ import print_function
import multiprocessing

def countdown(count):
    while count > 0:
        print("Count value", count)
        count -= 1
    return

if __name__ == "__main__":
    p1 = multiprocessing.Process(target=countdown, args=(10,))
    p1.start()

    p2 = multiprocessing.Process(target=countdown, args=(20,))
    p2.start()

    p1.join()
    p2.join()

這裡,每個函式都在一個新程序中執行。由於 Python VM 的新例項正在執行程式碼,因此沒有 GIL,你可以在多個核心上執行並行操作。

Process.start 方法啟動這個新程序,並使用引數 args 執行 target 引數中傳遞的函式。Process.join 方法等待程序 p1p2 的執行結束。

根據 python 的版本和執行程式碼的平臺形式,新程序的啟動方式不同,例如

  • Windows 使用 spawn 來建立新程序。
  • 對於 unix 系統和早於 3.3 的版本,使用 fork 建立流程。
    請注意,此方法不考慮 fork 的 POSIX 使用,因此會導致意外行為,尤其是在與其他多處理庫互動時。
  • 使用 unix 系統和 3.4+版本,你可以選擇在程式開始時使用 multiprocessing.set_start_method 啟動 forkforkserverspawn 的新流程。forkserverspawn 方法比分叉慢,但避免一些意想不到的行為。

POSIX fork 用法

在多執行緒程式中的 fork 之後,子程序可以安全地只呼叫非同步訊號安全函式,直到它呼叫 execve 為止。

使用 fork,將為所有當前互斥鎖啟動一個具有完全相同狀態的新程序,但只會啟動 MainThread。這是不安全的,因為它可能導致競爭條件,例如

  • 如果你在 MainThread 中使用 Lock 並將其傳遞給另一個執行緒,該執行緒可能會在某個時刻將其鎖定。如果 fork 同時發生,則新程序將以鎖定鎖啟動,該鎖將永遠不會釋放,因為此新程序中不存在第二個執行緒。

實際上,這種行為不應該在純 python 中發生,因為 multiprocessing 正確處理它,但如果你正在與其他庫互動,這種行為可能會發生,導致你的系統崩潰(例如在 macOS 上有 numpy /加速)。