簡體   English   中英

多處理pool.apply_async占用內存

[英]Multiprocessing pool.apply_async eats up memory

用例:

  1. 20億個參數組合可通過10台服務器(16核128GB RAM)進行處理
  2. 每個服務器使用pool.apply_async()處理2億個組合(Python版本3.7)
  3. 使總處理時間盡可能短

問題:

  1. Python吞噬了所有內存並拋出錯誤“ RuntimeError:無法啟動新線程 ”和“ OSError:[Errno 12]無法分配內存

我正在考慮將.apply_async()方法替換為.apply() ,但是我想通過將非阻塞模式更改為阻塞模式會嚴重影響總處理時間。

任何人都可以幫助找到這種情況下的最佳解決方案(最少的時間)嗎?

我的代碼:

exec_log = multiprocessing.Manager().list([0, ''])
lock = multiprocessing.Manager().Lock()
cores = multiprocessing.cpu_count()
pool = multiprocessing.Pool(processes=cores)

# Parameters a to j
for a in a_list: # a_list contains 2 elements
    for b in b_list: # b_list contains 2 elements
        for c in c_list: # c_list contains 5 elements
            for d in d_list: # d_list contains 10 elements
                for e in e_list: # e_list contains 10 elements
                    for f in f_list: # f_list contains 5 elements
                        for g in g_list: # g_list contains 20 elements
                            for h in h_list: # h_list contains 10 elements
                                for i in i_list: # i_list contains 10 elements
                                    for j in j_list: # j_list contains 10 elements
                                        pool.apply_async(prestart, (df, start_date, end_date, curr_date, 
                                                                    analysis_period, a, b, c, d, e,
                                                                    f, g, h, i, j, exec_log, lock))
pool.close()
pool.join()
logger.info(exec_log[1])

在這種情況下,誰能幫助找到最佳解決方案 (節省時間)

當然,讓我們檢查購物清單的可見部分:

1)
避免使用Lock() ,在任何形式的Lock() ing仍然存在的情況下,您希望對代碼執行進行並行組織會內化為阻塞狀態重新編排的純[SERIAL]一個接一個的(讓其余的都等待輪到它—無論數量多少,一個大型的RAM-on-Steriods服務器都在工作—全部等待着輪到他們,大部分時間都在嘗試“抓住” Lock()

2)
避免使用任何形式的共享 ,因為任何形式的共享資源都將保留,您希望擁有的並行工作流(再次)訴諸於等待任何此類共享資源從任何其他人的使用中解放出來並可能開始被這個過程所使用。

3)
避免任何過多的進程/內存實例化(除了您已經經歷的RAM崩潰崩潰之外,對於HPC級並行問題解決方案來說,這些開銷也過高-在以下兩種情況中:

  • [TIME]...實例化附加開銷...〜數以千計的[ns]
  • [SPACE] -domain ...新的內存分配要求由O / S以越來越大的規模以顯着的附加成本來處理,遠遠超過〜數以千計的[ns] ,最糟糕的情況是陷入了虛擬內存內存交換令人窒息……再次,為移動數據存儲塊支付了相關的[TIME]域費用(對於NUMA-CPU核心非本地RAM目的地+數據,RAM副本的成本約為300-350 [ns]基於卷的I / O帶寬驅動和可用RAM通道的可用性進一步限制了此類數據傳輸延遲,如果發生交換,則協調的O / S(即,在您的控制范圍之外)交換流會到達花費〜1,000 x〜10,000 x更糟...並且在該時間段內將計算和讀取/寫入RAM的任何其他嘗試列為最高優先級來進行阻塞,因此另一個原因是沒人希望在計算期間發生這些情況)

使用multiprocessing.get_all_start_methods()將顯示localhost O / S可以提供​​的所有選項,以消除(小規模緩解)不必要的過多RAM分配。

使用len( os.sched_getaffinity(0) )控件而不是上面使用的multiprocessing.cpu_count() ,將消除localhost超額訂購免費使用的CPU內核數量(也減少了“ just”副本的數量- [CONCURRENT] -RAM副本,必須等待其調度程序排序的輪次,然后才能輪流其RAM / CPU執行...),如果O / S關聯性映射策略限制用戶程序使用所有所示平台的硬件核心。


的“可怕” for基礎的“外” -迭代器總是可以得到改善,但核心戰略更重要的是:

可以將代碼重構為計算:

在花費了此類成本之后,一種以性能為重點的干凈的計算方法可以在現實成本與您將享受的凈性能收益之間取得平衡。

許多“精打細算”的方法無法遠遠超過一些主要的增長規模-首先,通過體驗In-CACHE計算中的驅逐罪而感受到RAM的實際成本(這在教科書示例中並未觀察到)和演示),接下來是In-RAM數據流的成本,對於越來越大的數據大小,最后但並非最不重要的是,來自多處理的天真期望的成本(取決於O / S和版本,引入了分配許多完整的python-session-replicas的世代附加成本,這可能會導致內存錯誤崩潰-就像上面發布的情況一樣)

假設10台服務器分別具有16個內核和128 GB RAM,那么有前途的舉動將在計算帶有數據的prestart()時測試python-proces的大小,然后在服務器內部產生更多“工人”,直到它們全部適合為止到RAM中(以避免交換),接下來創建一個消息傳遞/信令元層,以使用此高性能,低延遲工具(如ZeroMQ)來協調該分布式工作池中許多作業的智能參數傳遞或nanomsg,並設計工作流程,以使您永遠不會兩次傳遞單個數據(由於系統和O / S屬性,參數傳遞的附加成本比O(n)還要差),所以永遠不要移動在性能驅動型系統中兩次存儲一條數據。


遵循這些簡單的規則並不便宜,但是沒有更快的方法(免費提供的方法越少...)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM