簡體   English   中英

Python:多處理,加載8/24核心

[英]Python: multiprocessing, 8/24 cores loaded

我有一台機器有24個物理內核 (至少我被告知)運行Debian: Linux 3.2.0-4-amd64 #1 SMP Debian 3.2.68-1+deb7u1 x86_64 GNU/Linux 這似乎是正確的:

usr@machine:~/$ cat /proc/cpuinfo  | grep processor
processor   : 0
processor   : 1
<...>
processor   : 22
processor   : 23

嘗試使用Python的multiprocessing.pool.Pool加載所有內核時遇到了一些問題。 我用了Pool(processes=None) ; 文檔說如果提供None ,Python使用cpu_count()

唉, 只有8個核心100%加載 ,其他核心仍處於空閑狀態(我使用htop來監控CPU負載)。 我以為我無法正確地烹飪Pools並嘗試“手動”調用24個進程:

print 'Starting processes...'
procs = list()
for param_set in all_params:  # 24 items
    p = Process(target=_wrap_test, args=[param_set])
    p.start()
    procs.append(p)

print 'Now waiting for them.'
for p in procs:
    p.join()

我從我開始的流程中收到了24條“問候”消息:

Starting processes...
Executing combination: Session len: 15, delta: 10, ratio: 0.1, eps_relabel: 0.5, min_pts_lof: 5, alpha: 0.01, reduce: 500
< ... 22 more messages ... >
Executing combination: Session len: 15, delta: 10, ratio: 0.1, eps_relabel: 0.5, min_pts_lof: 7, alpha: 0.01, reduce: 2000
Now waiting for them.

仍然只加載了8個核心

在此輸入圖像描述

我在這里看到, numpy ,OpenBLAS和多核執行可能存在問題。 這就是我啟動代碼的方式:

OPENBLAS_MAIN_FREE=1 python -m tests.my_module

在完成所有進口之后我做了:

os.system("taskset -p 0xff %d" % os.getpid())

所以,問題是:我應該怎樣做才能在所有內核上實現100%的負載? 這只是我糟糕的Python使用情況還是與多核計算機上的操作系統限制有關?

更新 :另一個有趣的事情是htop輸出中的一些不一致。 如果你看一下上面的圖像,你會發現CPU負載條下面的表顯示了超過8個內核的30-50%負載,這與負載條所說的完全不同。 然后, top似乎同意這些條:8個核心100%負載,其他閑置。

再次更新:

當我在所有導入后添加os.system("taskset -p 0xff %d" % os.getpid())行時,我在SO上使用了這個相當受歡迎的帖子 我必須承認,當我這樣做時,我並沒有想太多,特別是在閱讀之后:

在模塊導入后粘貼此行,我的示例現在在所有核心上運行

我是一個單純的男人。 我看到“像魅力一樣”,我復制並粘貼。 無論如何,在玩我的代碼時,我最終刪除了這一行。 之后,我的代碼開始在所有24個核心上執行“手動” Process啟動方案。 對於Pool場景,無論是否使用了關聯技巧,仍然存在同樣的問題。

我認為這不是一個真正的答案,因為我不知道Pool的問題是什么,但至少我設法讓所有核心都滿載。 謝謝!

即使你解決了這個問題,我也會嘗試解釋它以澄清這些想法。

對於我所讀到的內容,numpy為提高性能做了很多“魔術”。 其中一個神奇的技巧是設置進程的CPU親和力。

CPU親和性是OS調度程序的優化。 它基本上強制給定的進程始終在同一CPU核心上運行。

這樣可以提高性能,減少CPU緩存失效的次數,並提高參考局部性的優勢。 在高計算任務中,這些因素確實很重要。

我不喜歡numpy的事實是它隱含地做了所有這些。 經常讓開發人員感到困惑。

您的進程未在所有核心上運行的事實是由於numpy在導入模塊時為父進程設置了親和關系。 然后,當您生成新進程時,將繼承關聯,導致所有進程爭用少數核心,而不是有效地使用所有可用的進程。

os.system("taskset -p 0xff %d" % os.getpid())命令指示操作系統在解決問題的所有核心上設置關聯。

如果你想看到它在Pool上工作,你可以做以下技巧。

import os
from multiprocessing import Pool


def set_affinity_on_worker():
    """When a new worker process is created, the affinity is set to all CPUs"""
    print("I'm the process %d, setting affinity to all CPUs." % os.getpid())
    os.system("taskset -p 0xff %d" % os.getpid())


if __name__ == '__main__':
    p = Pool(initializer=set_affinity_on_worker)
    ...

os.system("taskset -p 0xff %d" % os.getpid())0xff本質上是十六進制位掩碼,對應於1111 1111.位掩碼中的每個位對應一個CPU內核。 位值1表示可以在相應的CPU內核上執行該過程。 因此,要在24個內核上運行,您應該使用0xffffff而不是0xff的掩碼。

正確的命令:

os.system("taskset -p 0xffffff %d" % os.getpid())

暫無
暫無

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

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