Multiprocessing package – torch.multiprocessing

  • 2019 年 10 月 5 日
  • 筆記

版權聲明:本文為部落客原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。

本文鏈接:https://blog.csdn.net/weixin_36670529/article/details/100928734

torch.multiprocessing是圍繞本機多處理模組的包裝器。它註冊自定義約簡器,使用共享記憶體在不同進程中提供對相同數據的共享視圖。一旦張量/存儲被移動到shared_memory(請參閱share_memory_()),就可以將它發送到其他進程,而不需要進行任何複製。

該API與原始模組100%兼容—只需更改導入多處理即可導入torch。多處理將所有張量通過隊列發送或通過其他機制共享,移動到共享記憶體。由於api的相似性,我們不記錄這個包的大部分內容,我們建議參考原始模組中非常好的文檔。

Warning

如果主進程突然退出(例如,由於傳入的訊號),Python的多處理有時無法清理其子進程。這是一個已知的警告,因此,如果你在中斷解釋器之後看到任何資源泄漏,這可能意味著這只是發生在你身上。

Strategy management

torch.multiprocessing.get_all_sharing_strategies()[source]

返回當前系統支援的一組共享策略。

torch.multiprocessing.get_sharing_strategy()[source]

返回共享CPU張量的當前策略。

torch.multiprocessing.set_sharing_strategy(new_strategy)[source]

設置共享CPU張量的策略。

Parameters

new_strategy (str) -所選策略的名稱。應該是get_all_sharing_strategies()返回的值之一。

Sharing CUDA tensors

進程之間共享CUDA張量僅在python3中受支援,使用派生或forkserver啟動方法。Python 2中的多處理只能使用fork創建子進程,而且CUDA運行時不支援它。與CPU張量不同,發送過程需要保持原始張量,只要接收過程保留張量的副本。refcount是在底層實現的,但要求用戶遵循下一個最佳實踐。

Warning

如果使用者進程非正常地死於一個致命的訊號,那麼只要發送進程在運行,共享張量就可以永遠保存在記憶體中。

1. 儘快在用戶中釋放記憶體。

## 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()

Sharing strategies

本節簡要概述了不同的共享策略是如何工作的。注意,它只適用於CPU張量——CUDA張量總是使用CUDA API,因為這是它們可以共享的唯一方式。

File descriptor – file_descriptor

Note

這是默認策略(不支援macOS和OS X的情況除外)。此策略將使用文件描述符作為共享記憶體句柄。每當一個存儲被移動到共享記憶體時,從shm_open獲得的文件描述符就與該對象一起快取,當它被發送到其他進程時,文件描述符將被傳輸到它(例如,通過UNIX套接字)。接收方還將快取文件描述符並映射它,以獲得存儲數據上的共享視圖。注意,如果有很多張量共享,這種策略將在大多數時間保持大量的文件描述符打開。如果您的系統對打開的文件描述符的數量有較低的限制,並且您不能提高它們,那麼您應該使用file_system策略。

File system – file_system

該策略將使用指定給shm_open的文件名來標識共享記憶體區域。這樣做的好處是不需要實現快取從中獲得的文件描述符,但同時容易出現共享記憶體泄漏。文件創建後不能立即刪除,因為其他進程需要訪問它才能打開它們的視圖。如果進程致命地崩潰,或者被殺死,並且不調用存儲析構函數,文件將保留在系統中。這是非常嚴重的,因為它們會一直使用記憶體,直到系統重新啟動,或者手動釋放它們。為了解決共享記憶體文件泄漏的問題,torch。多處理將生成一個名為torch_shm_manager的守護進程,該守護進程將自己與當前進程組隔離,並跟蹤所有共享記憶體分配。一旦連接到它的所有進程退出,它將等待片刻以確保沒有新的連接,並將迭代組分配的所有共享記憶體文件。如果它發現它們中的任何一個仍然存在,就會釋放它們。我們對該方法進行了測試,證明該方法對各種故障具有較強的魯棒性。不過,如果您的系統有足夠高的限制,並且file_descriptor是受支援的策略,我們不建議切換到這個策略。

Spawning subprocesses

Note

該策略將使用指定給shm_open的文件名來標識共享記憶體區域。這樣做的好處是不需要實現快取從中獲得的文件描述符,但同時容易出現共享記憶體泄漏。文件創建後不能立即刪除,因為其他進程需要訪問它才能打開它們的視圖。如果進程致命地崩潰,或者被殺死,並且不調用存儲析構函數,文件將保留在系統中。這是非常嚴重的,因為它們會一直使用記憶體,直到系統重新啟動,或者手動釋放它們。適用於Python >= 3.4。這取決於Python的多處理包中的spawn start方法。通過創建流程實例並調用join來等待它們的完成,可以生成許多子流程來執行某些功能。這種方法在處理單個子流程時工作得很好,但在處理多個流程時存在潛在問題。也就是說,按順序連接進程意味著它們將按順序終止。如果沒有,並且第一個進程沒有終止,則進程終止將不被注意。此外,沒有用於錯誤傳播的本機工具。下面的spawn函數處理這些問題,並處理錯誤傳播、無序終止,並在檢測到其中一個錯誤時主動終止進程。

torch.multiprocessing.spawn(fn, args=(), nprocs=1, join=True, daemon=False)[source]

生成使用args運行fn的nprocs進程。

如果其中一個進程以非零的退出狀態退出,則其他進程將被終止,並引發一個異常,原因是終止。在子進程中捕獲異常的情況下,將轉發該異常並將其回溯包含在父進程中引發的異常中。

Parameters

  • fn (function) – 函數被稱為派生進程的入口點。此函數必須在模組的頂層定義,以便對其進行pickle和派生。這是多處理強加的要求。該函數被稱為fn(i, *args),其中i是進程索引,args是通過參數元組傳遞的。
  • args (tuple) – 參數傳遞給fn。
  • nprocs (int) – 要生成的進程數。
  • join (bool) – 對所有進程執行阻塞連接。
  • daemon (bool) – 派生進程的守護進程標誌。如果設置為True,將創建守護進程。

Returns

None if join is True, SpawnContext if join is False

class torch.multiprocessing.SpawnContext[source]

Returned by spawn() when called with join=False.

join(timeout=None)[source]

嘗試在此派生上下文中聯接一個或多個進程。如果其中一個進程以非零退出狀態退出,則此函數將終止其餘進程,並引發一個異常,原因是第一個進程退出。如果所有進程都已成功連接,則返回True;如果需要連接更多進程,則返回False。

Parameters

timeout (float) – Wait this long before giving up on waiting.