2015-12-15 66 views
2

在我使用的linux系統上,調度程序並不是非常慷慨,給cpu時間從python的多處理模塊產生的子進程。在4核機器上使用4個子處理器時,根據ps,我可以獲得22%左右的CPU。但是,如果子進程是shell的子進程,而不是python程序,它會達到接近100%的CPU。但是多處理是一個比手動分割數據更好的接口,並且爲每個分割運行單獨的python程序,並且很好地獲得兩全其美(代碼組織和高CPU使用率)。我嘗試將流程的好壞設置爲-20,但這沒有幫助。操作系統級別的變化加速Python的多處理?

我想知道是否用一些選項重新編譯linux內核將有助於調度程序給予python多進程工作者更多的CPU時間。也許有一個相關的配置選項?

我使用的準確版本是:

$ uname -a 
Linux <hostname> 3.19.0-39-generiC#44~14.04.1-Ubuntu SMP Wed Dec 2 10:00:35 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux 

在這種情況下,可能與我使用多的方式,它的形式是:

with Pool(4) as p: 
    p.map(function,data) 

更新: 這不是一個可重現的問題。這裏報告的結果來自幾天前,我再次進行測試,多處理過程如我所願。也許這個問題應該被刪除,誤導人們對multiprocessing的期望表現會不太好。

+2

你確定這是內核的責任嗎?這個問題似乎與Python無法真正並行運行作業有關。 – 5gon12eder

+0

多進程工作人員是他們自己的進程與他們自己的PID。這是我的理解,使得這些流程彼此截然不同,例如我的網絡瀏覽器。 – seewalker

+1

你可以[很容易]飽和你的內存總線(即)你內存綁定,不受計算限制。也許,你可以估計或基準確認。看看/ sys/devices/system/cpu/cpu */cpufreq並設置爲「performance」 –

回答

2

我不相信你的基準測試可以像你認爲的那樣作爲獨立的任務執行。你沒有顯示function的代碼,但我懷疑它做了一些同步。

我寫了以下基準。如果我使用​​或--mp選項運行腳本,我總能獲得400%的CPU利用率(在我的四核機器上)和大約18秒的可比較總體執行時間。但是,如果使用--threads選項調用,程序將有效地按順序運行,僅實現大約100%的CPU利用率,並由於mentioned by dave需要一分鐘才能完成。

import multiprocessing 
import os 
import random 
import sys 
import threading 


def find_lucky_number(x): 
    prng = random.Random() 
    prng.seed(x) 
    for i in range(100000000): 
     prng.random() 
    return prng.randint(0, 100) 

def with_threading(inputs): 
    callback = lambda x : print(find_lucky_number(x)) 
    threads = [threading.Thread(target=callback, args=(x,)) for x in inputs] 
    for t in threads: 
     t.start() 
    for t in threads: 
     t.join() 

def with_multiprocessing(inputs): 
    with multiprocessing.Pool(len(inputs)) as pool: 
     for y in pool.map(find_lucky_number, inputs): 
      print(y) 

def with_forking(inputs): 
    pids = list() 
    for x in inputs: 
     pid = os.fork() 
     if pid == 0: 
      print(find_lucky_number(x)) 
      sys.exit(0) 
     else: 
      pids.append(pid) 
    for pid in pids: 
     os.waitpid(pid, 0) 

if __name__ == '__main__': 
    inputs = [1, 2, 3, 4] 
    if sys.argv[1] == '--threads': 
     with_threading(inputs) 
    if sys.argv[1] == '--mp': 
     with_multiprocessing(inputs) 
    elif sys.argv[1] == '--fork': 
     with_forking(inputs) 
    else: 
     print("What should I do?", file=sys.stderr) 
     sys.exit(1) 
+0

我所做的非常像你的with_multiprocessing函數:在一個帶Pool的環境中啓動進程,沒有同步或共享內存。我報告的結果是幾天前發生的事情,我試着再次運行它,結果更像您發現的結果。我正在考慮刪除問題,因爲這不是一個可重現的問題。也許主持人知道是否值得這樣做,因爲你已經提出了一些好的觀點。 – seewalker

+0

@seewalker我不知道這種情況下最好的解決方案是什麼。我們都不能像現在這樣刪除問題。我不知道標記是否合適,但它是一種選擇。另一方面,您可以嘗試重新提出您的問題以問「如何讓Python利用所有CPU?」。但請注意不要提問即時關閉的重複項目。 – 5gon12eder

+0

我會離開這個問題,部分原因是@ 5gon12eder的答案。他的測試程序使其值得。而且,我是一個長期的程序員,但是Python新手,所以我從中得到了一些東西。但是,我使用線程或進程與perl WRT分裂有類似的問題。即使它不可重現,問題和答案都是明確的[和高投訴]。我看到很多問題留下來,OP重試並得到不同的結果。你用免責聲明編輯了這個問題 - 你在法律上和道德上都被覆蓋了。國際海事組織,主持人有更大的魚炒,沒有傷害,這裏沒有犯規。 –

1

歡迎來到CPython Global Interpreter Lock。你的線程顯示爲與Linux內核截然不同的進程(這就是線程在Linux中的實現方式:每個線程都有自己的進程,因此內核可以調度它們)。

那麼,爲什麼Linux不是每次都調度其中的一個以上(這就是爲什麼你的4核心機器平均減少25%左右的開銷)? python解釋器在解釋每個線程時持有一個鎖,從而阻止其他線程運行(所以它們不能被調度)。

要解決這個問題,您可以:

  1. 使用過程而不是線程(如你在你的問題提)
  2. 使用不具有全局解釋器鎖不同的Python解釋器。
+0

在所有方面,我不認爲這是正確的答案。文檔的第一段說:* multiprocessing'是一個使用類似於'threading'模塊的API支持產卵過程的軟件包。 'multiprocessing'包提供本地和遠程併發性,通過使用子進程而不是線程有效地側移全局解釋器鎖。* – 5gon12eder

+0

是的,我認爲這是正確的答案可能爲時過早。我遇到的特殊情況可能是Global Interpreter Lock相關(感謝dave!),但是感謝您注意到多處理並不與該鎖緊密相關。 – seewalker

相關問題