多程序套件 - torch.multiprocessing¶
torch.multiprocessing 是原生 multiprocessing 模組的包裝函式。
它會註冊自訂的 reducer,這些 reducer 使用共用記憶體來在不同程序中提供對相同資料的共用檢視。將張量/儲存體移至共用記憶體後(請參閱 share_memory_()),就可以將其傳送到其他程序,而無需進行任何複製。
API 與原始模組 100% 相容 - 只需將 import multiprocessing 改為 import torch.multiprocessing,即可將所有透過佇列傳送或透過其他機制共用的張量移至共用記憶體。
由於 API 的相似性,我們不會記錄此套件大部分的內容,建議您參閱原始模組的完整文件。
警告
如果主程序突然退出(例如,因為收到信號),Python 的 multiprocessing 有時無法清除其子程序。這是一個已知的警告,因此如果您在中斷直譯器後看到任何資源洩漏,這可能表示您剛剛遇到了這種情況。
策略管理¶
- torch.multiprocessing.set_sharing_strategy(new_strategy)[原始碼]¶
- 設定共用 CPU 張量的策略。 - 參數
- new_strategy (str) – 所選策略的名稱。應該是 - get_all_sharing_strategies()傳回的值之一。
 
共用 CUDA 張量¶
僅在 Python 3 中支援在程序之間共用 CUDA 張量,使用 spawn 或 forkserver 啟動方法。
與 CPU 張量不同,傳送程序必須保留原始張量,只要接收程序保留張量的副本。引用計數是在底層實作的,但需要使用者遵循以下最佳實務。
警告
如果消費者程序因為致命信號而異常終止,則共用張量可能會永遠保留在記憶體中,只要傳送程序正在執行。
- 盡快在消費者中釋放記憶體。 
## Good
x = queue.get()
# do somethings with x
del x
## Bad
x = queue.get()
# do somethings with x
# do everything else (producer have to keep x in memory)
2. 讓生產者程序持續執行,直到所有消費者退出為止。這將防止生產者程序釋放消費者仍在使用的記憶體的情況。
## producer
# send tensors, do something
event.wait()
## consumer
# receive tensors and use them
event.set()
- 不要傳遞接收到的張量。 
# not going to work
x = queue.get()
queue_2.put(x)
# you need to create a process-local copy
x = queue.get()
x_clone = x.clone()
queue_2.put(x_clone)
# putting and getting from the same queue in the same process will likely end up with segfault
queue.put(tensor)
x = queue.get()
共用策略¶
本節簡要概述了不同共用策略的工作原理。請注意,這僅適用於 CPU 張量 - CUDA 張量將始終使用 CUDA API,因為這是它們可以共用的唯一方式。
檔案描述符 - file_descriptor¶
注意事項
這是預設策略(macOS 和 OS X 除外,因為它們不支援此策略)。
此策略將使用檔案描述符作為共用記憶體控制代碼。每當儲存體移至共用記憶體時,從 shm_open 取得的檔案描述符會與物件一起快取,並且當它要傳送到其他程序時,檔案描述符將會傳輸(例如,透過 UNIX 通訊端)到該程序。接收器也會快取檔案描述符並對其執行 mmap,以取得儲存體資料的共用檢視。
請注意,如果有很多張量要共用,此策略會在大部分時間內保持大量檔案描述符處於開啟狀態。如果您的系統對開啟檔案描述符的數量有限制,並且您無法提高限制,則應使用 file_system 策略。
檔案系統 - file_system¶
此策略將使用提供給 shm_open 的檔案名稱來識別共享記憶體區域。這樣做的好處是不需要實作快取從中取得的檔案描述符,但同時也容易發生共享記憶體洩漏。檔案建立後無法立即刪除,因為其他行程需要存取它才能開啟其檢視。如果行程嚴重損毀或被終止,且沒有呼叫儲存空間解構函式,則檔案將會保留在系統中。這非常嚴重,因為它們會持續佔用記憶體,直到系統重新啟動或手動釋放它們為止。
為了應對共享記憶體檔案洩漏的問題,torch.multiprocessing 將會產生一個名為 torch_shm_manager 的常駐程式,它會將自身與目前的行程群組隔離,並持續追蹤所有共享記憶體配置。一旦所有連接到它的行程都結束,它會等待一段時間,以確保沒有新的連線,然後逐一檢查群組配置的所有共享記憶體檔案。如果它發現其中任何一個仍然存在,它們將會被釋放。我們已經測試過這個方法,它證明可以有效應對各種故障。儘管如此,如果您的系統限制夠高,且 file_descriptor 是支援的策略,我們不建議切換到這個策略。
產生子行程¶
注意事項
適用於 Python >= 3.4。
這取決於 Python 的 multiprocessing 套件中的 spawn 啟動方法。
可以透過建立 Process 實例並呼叫 join 來等待它們完成,以產生多個子行程來執行某些函式。這種方法在處理單一子行程時運作良好,但在處理多個行程時會出現潛在問題。
也就是說,依序加入行程意味著它們將會依序終止。如果它們沒有依序終止,且第一個行程沒有終止,則行程終止將不會被注意到。此外,也沒有原生機制可以進行錯誤傳播。
以下的 spawn 函式解決了這些問題,並處理錯誤傳播、無序終止,並在偵測到其中一個行程發生錯誤時主動終止行程。
- torch.multiprocessing.spawn.spawn(fn, args=(), nprocs=1, join=True, daemon=False, start_method='spawn')[source]¶
- 產生 - nprocs個行程,這些行程會使用- args執行- fn。- 如果其中一個行程以非零的結束狀態結束,則其餘行程將會被終止,並會產生一個包含終止原因的例外狀況。如果在子行程中攔截到例外狀況,則會將其轉發,並將其追蹤資訊包含在父行程中產生的例外狀況中。 - 參數
- **fn** ( *函式* ) – - 函式會作為產生行程的進入點被呼叫。此函式必須在模組的最上層定義,以便可以對其進行序列化和產生。這是多行程處理所施加的要求。 - 函式會以 - fn(i, *args)的形式被呼叫,其中- i是行程索引,而- args是傳遞的參數元組。
- **args** ( *元組* ) – 傳遞給 - fn的參數。
- **nprocs** ( *整數* ) – 要產生的行程數量。 
- **join** ( *布林值* ) – 對所有行程執行阻擋式加入。 
- **daemon** ( *布林值* ) – 產生行程的常駐程式旗標。如果設定為 True,則會建立常駐行程。 
- **start_method** ( *字串* ) – (已棄用) 此方法將始終使用 - spawn作為啟動方法。若要使用其他啟動方法,請使用- start_processes()。
 
- 傳回值
- 如果 - join為- True,則為 None,如果- join為- False,則為- ProcessContext