python3從零學習-5.6.8、multiprocessing進程模塊

源代碼 Lib/multiprocessing/

multiprocessing 是一個用與 threading 模塊相似API的支持產生進程的包。 multiprocessing 包同時提供本地和遠程併發,使用子進程代替線程,有效避免 Global Interpreter Lock 帶來的影響。因此, multiprocessing 模塊允許程序員充分利用機器上的多個核心。Unix 和 Windows 上都可以運行。

multiprocessing 模塊還引入了在 threading 模塊中沒有類似物的API。這方面的一個主要例子是 Pool 對象,它提供了一種方便的方法,可以跨多個輸入值並行化函數的執行,跨進程分配輸入數據(數據並行)。以下示例演示了在模塊中定義此類函數的常見做法,以便子進程可以成功導入該模塊。

Process 類

在 multiprocessing 中,通過創建一個 Process 對象然後調用它的 start() 方法來生成進程。 Process 和 threading.Thread API 相同。 一個簡單的多進程程序示例是:

from multiprocessing import Process

def f(name):
    print('hello', name)

if __name__ == '__main__':
    p = Process(target=f, args=('bob',))
    p.start()
    p.join()

根據不同的平臺, multiprocessing 支持三種啓動進程的方法。這些 啓動方法 有

 

  • spawn

父進程啓動一個新的Python解釋器進程。子進程只會繼承那些運行進程對象的 run() 方法所需的資源。特別是父進程中非必須的文件描述符和句柄不會被繼承。相對於使用 fork 或者 forkserver,使用這個方法啓動進程相當慢。

可在Unix和Windows上使用。 Windows上的默認設置。

 

  • fork

父進程使用 os.fork() 來產生 Python 解釋器分叉。子進程在開始時實際上與父進程相同。父進程的所有資源都由子進程繼承。請注意,安全分叉多線程進程是棘手的。

只存在於Unix。Unix中的默認值。

 

  • forkserver

程序啓動並選擇* forkserver * 啓動方法時,將啓動服務器進程。從那時起,每當需要一個新進程時,父進程就會連接到服務器並請求它分叉一個新進程。分叉服務器進程是單線程的,因此使用 os.fork() 是安全的。沒有不必要的資源被繼承。

可在Unix平臺上使用,支持通過Unix管道傳遞文件描述符。

在進程之間交換對象

 

multiprocessing 支持進程之間的兩種通信通道:

  • 隊列

Queue 類是一個近似 queue.Queue 的克隆。 例如:

from multiprocessing import Process, Queue

def f(q):
    q.put([42, None, 'hello'])

if __name__ == '__main__':
    q = Queue()
    p = Process(target=f, args=(q,))
    p.start()
    print(q.get())    # prints "[42, None, 'hello']"
    p.join()

隊列是線程和進程安全的。

 

  • 管道

 

Pipe() 函數返回一個由管道連接的連接對象,默認情況下是雙工(雙向)。例如:

from multiprocessing import Process, Pipe

def f(conn):
    conn.send([42, None, 'hello'])
    conn.close()

if __name__ == '__main__':
    parent_conn, child_conn = Pipe()
    p = Process(target=f, args=(child_conn,))
    p.start()
    print(parent_conn.recv())   # prints "[42, None, 'hello']"
    p.join()

返回的兩個連接對象 Pipe() 表示管道的兩端。每個連接對象都有 send() 和 recv() 方法(相互之間的)。請注意,如果兩個進程(或線程)同時嘗試讀取或寫入管道的 同一 端,則管道中的數據可能會損壞。當然,同時使用管道的不同端的進程不存在損壞的風險。

Process 和異常

 

class multiprocessing.Process(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)

進程對象表示在單獨進程中運行的活動。 Process 類等價於 threading.Thread 。

 

應始終使用關鍵字參數調用構造函數。 group 應該始終是 None ;它僅用於兼容 threading.Thread 。 target 是由 run() 方法調用的可調用對象。它默認爲 None ,意味着什麼都沒有被調用。 name 是進程名稱(有關詳細信息,請參閱 name )。 args 是目標調用的參數元組。 kwargs 是目標調用的關鍵字參數字典。如果提供,則鍵參數 daemon 將進程 daemon 標誌設置爲 True 或 False 。如果是 None (默認值),則該標誌將從創建的進程繼承。

 

默認情況下,不會將任何參數傳遞給 target 。

 

如果子類重寫構造函數,它必須確保它在對進程執行任何其他操作之前調用基類構造函數( Process.__init__() )。

 

在 3.3 版更改: 加入 daemon 參數。

 

run()

表示進程活動的方法。

 

你可以在子類中重載此方法。標準 run() 方法調用傳遞給對象構造函數的可調用對象作爲目標參數(如果有),分別從 args 和 kwargs 參數中獲取順序和關鍵字參數。

 

start()

啓動進程活動。

 

每個進程對象最多隻能調用一次。它安排對象的 run() 方法在一個單獨的進程中調用。

 

join([timeout])

如果可選參數 timeout 是 None (默認值),則該方法將阻塞,直到調用 join() 方法的進程終止。如果 timeout 是一個正數,它最多會阻塞 timeout 秒。請注意,如果進程終止或方法超時,則該方法返回 None 。檢查進程的 exitcode 以確定它是否終止。

 

一個進程可以合併多次。

 

進程無法併入自身,因爲這會導致死鎖。嘗試在啓動進程之前合併進程是錯誤的。

 

name

進程的名稱。該名稱是一個字符串,僅用於識別目的。它沒有語義。可以爲多個進程指定相同的名稱。

 

初始名稱由構造器設定。 如果沒有爲構造器提供顯式名稱,則會構造一個形式爲 ‘Process-N1:N2:…:Nk’ 的名稱,其中每個 Nk 是其父親的第 N 個孩子。

 

is_alive()

返回進程是否還活着。

 

粗略地說,從 start() 方法返回到子進程終止之前,進程對象仍處於活動狀態。

 

daemon

進程的守護標誌,一個布爾值。這必須在 start() 被調用之前設置。

 

初始值繼承自創建進程。

 

當進程退出時,它會嘗試終止其所有守護進程子進程。

 

請注意,不允許守護進程創建子進程。否則,守護進程會在子進程退出時終止其子進程。 另外,這些 不是 Unix守護進程或服務,它們是正常進程,如果非守護進程已經退出,它們將被終止(並且不被合併)。

 

除了 threading.Thread API ,Process 對象還支持以下屬性和方法:

 

pid

返回進程ID。在生成該進程之前,這將是 None 。

 

exitcode

的退子進程出代碼。如果進程尚未終止,這將是 None 。負值 -N 表示孩子被信號 N 終止。

 

authkey

進程的身份驗證密鑰(字節字符串)。

 

當 multiprocessing 初始化時,主進程使用 os.urandom() 分配一個隨機字符串。

 

當創建 Process 對象時,它將繼承其父進程的身份驗證密鑰,儘管可以通過將 authkey 設置爲另一個字節字符串來更改。

 

參見 認證密碼 。

 

sentinel

系統對象的數字句柄,當進程結束時將變爲 “ready” 。

 

如果要使用 multiprocessing.connection.wait() 一次等待多個事件,可以使用此值。否則調用 join() 更簡單。

 

在Windows上,這是一個操作系統句柄,可以與 WaitForSingleObject 和 WaitForMultipleObjects 系列API調用一起使用。在Unix上,這是一個文件描述符,可以使用來自 select 模塊的原語。

 

3.3 新版功能.

 

terminate()

終止進程。 在Unix上,這是使用 SIGTERM 信號完成的;在Windows上使用 TerminateProcess() 。 請注意,不會執行退出處理程序和finally子句等。

 

請注意,進程的後代進程將不會被終止 —— 它們將簡單地變成孤立的。

 

警告 如果在關聯進程使用管道或隊列時使用此方法,則管道或隊列可能會損壞,並可能無法被其他進程使用。類似地,如果進程已獲得鎖或信號量等,則終止它可能導致其他進程死鎖。

注意 start() 、 join() 、 is_alive() 、 terminate() 和 exitcode 方法只能由創建進程對象的進程調用。

 

Process 一些方法的示例用法:

>>> import multiprocessing, time, signal
>>> p = multiprocessing.Process(target=time.sleep, args=(1000,))
>>> print(p, p.is_alive())
<Process(Process-1, initial)> False
>>> p.start()
>>> print(p, p.is_alive())
<Process(Process-1, started)> True
>>> p.terminate()
>>> time.sleep(0.1)
>>> print(p, p.is_alive())
<Process(Process-1, stopped[SIGTERM])> False
>>> p.exitcode == -signal.SIGTERM
True

exception multiprocessing.ProcessError

所有 multiprocessing 異常的基類。

 

exception multiprocessing.BufferTooShort

當提供的緩衝區對象太小而無法讀取消息時, Connection.recv_bytes_into() 引發的異常。

 

如果 e 是一個 BufferTooShort 實例,那麼 e.args[0] 將把消息作爲字節字符串給出。

 

exception multiprocessing.AuthenticationError

出現身份驗證錯誤時引發。

 

exception multiprocessing.TimeoutError

有超時的方法超時時引發。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章