2011-07-26 41 views
2

我有我運行一個命令行程序,我管文字作爲參數:python中map.pool的用法是什麼?

somecommand.exe < someparameters_tin.txt

它運行了一段時間(通常是一個小時的良好的比例爲幾小時),然後將結果寫入多個文本文件。我試圖編寫一個腳本來同時啓動其中幾個,使用多核心機器上的所有內核。在其他操作系統上,我會分叉,但是這在Windows的很多腳本語言中都沒有實現。 Python的多處理看起來可能會有所斬獲,所以我想我會試一試,儘管我根本不知道python。我希望有人能告訴我我做錯了什麼。

我寫了一個腳本(下面),我指向一個目錄,如果找到可執行文件和輸入文件,並使用pool.map和一個n池以及使用調用的函數啓動它們。我看到的是,最初(第一組n進程啓動)看起來很好,使用n個內核100%。但後來我看到這些進程閒置,沒有使用或僅佔其CPU的百分之幾。那裏總是有n個流程,但他們沒有太多的工作。它似乎發生在編寫輸出數據文件時,一旦它開始一切都陷入泥潭,整體核心利用率從幾個百分點到50-60%的偶爾峯值,但從未接近100%。

如果我可以附加它(編輯:我不能,至少現在)這裏是過程的運行時間陰謀。較低的曲線是當我打開n個命令提示符並手動保存n個進程時,輕鬆保持計算機接近100%。 (這條線是規則的,在32個不同的過程中,從一個參數緩慢增加到接近0到0.7個小時)。上面一行是這個腳本的一些版本的結果 - 運行時間平均膨脹大約0.2小時,並且是更不容易預測,就像我已經取得了底線並增加了0.2 +一個隨機數。

下面是劇情的鏈接: Run time plot

編輯:現在我想我可以添加的情節。 enter image description here

我在做什麼錯?

from multiprocessing import Pool, cpu_count, Lock 
from subprocess import call 
import glob, time, os, shlex, sys 
import random 

def launchCmd(s): 
    mypid = os.getpid() 
    try: 
     retcode = call(s, shell=True) 
     if retcode < 0: 
      print >>sys.stderr, "Child was terminated by signal", -retcode 
     else: 
      print >>sys.stderr, "Child returned", retcode 
    except OSError, e: 
     print >>sys.stderr, "Execution failed:", e 

if __name__ == '__main__': 

    # ****************************************************************** 
    # change this to the path you have the executable and input files in 
    mypath = 'E:\\foo\\test\\' 
    # ****************************************************************** 

    startpath = os.getcwd() 
    os.chdir(mypath) 
    # find list of input files 
    flist = glob.glob('*_tin.txt') 
    elist = glob.glob('*.exe') 
    # this will not act as expected if there's more than one .exe file in that directory! 
    ex = elist[0] + ' < ' 

    print 
    print 'START' 
    print 'Path: ', mypath 
    print 'Using the executable: ', ex 
    nin = len(flist) 
    print 'Found ',nin,' input files.' 
    print '-----' 
    clist = [ex + s for s in flist] 
    cores = cpu_count() 
    print 'CPU count ', cores 
    print '-----' 

    # ****************************************************** 
    # change this to the number of processes you want to run 
    nproc = cores -1 
    # ****************************************************** 

    pool = Pool(processes=nproc, maxtasksperchild=1) # start nproc worker processes 
    # mychunk = int(nin/nproc)  # this didn't help 
    # list.reverse(clist)   # neither did this, or randomizing the list 
    pool.map(launchCmd, clist)  # launch processes 
    os.chdir(startpath)    # return to original working directory 
    print 'Done' 
+0

你看起來像你真的知道你在做什麼;這看起來像一個自稱爲總新手的好Python。一個問題:當CPU空閒時,硬​​盤是否超級忙?從理論上講,如果你的進程產生了大量的輸出,那麼在等待磁盤寫入所有內容時,進程可能大部分是空閒的。如果緩存由於某種原因不起作用,情況尤其如此。 – steveha

+0

看來(如資源監視器報告的),當CPU使用率下降(這是在第一個進程開始寫入其輸出時發生)時,磁盤活動會出現峯值,然後在所有進程完成之前保持接近100%。磁盤隊列也會變爲50.我很好奇爲什麼會出現這種情況,但不是當我從多個命令行手動執行相同的命令時 - 看起來似乎正在共享某些東西(很糟糕)。 – Brian

+0

我應該補充一點:我不在乎這些過程以什麼順序完成。在這個例子中,我正在嘗試最短的那個先運行。隨機或反轉訂單可能會有所幫助,但不會產生很大的差異。 – Brian

回答

0

進程是否有嘗試寫入通用文件的機會?在Linux下它可能會工作,打破數據但不會放慢速度;但是在Windows下,一個進程可能會獲得該文件,並且所有其他進程可能會掛起等待該文件可用。

如果用一些使用CPU但不寫入磁盤的愚蠢任務替換實際任務列表,問題是否會重現?例如,您可以擁有計算某個大文件的md5sum的任務;一旦文件被緩存,其他任務將是純CPU,然後將單行輸出到stdout。或者計算一些昂貴的功能或其他。

0

認爲我知道這一點。當您致電map時,它會將每個過程的任務列表分成「塊」。默認情況下,它使用足夠大的塊,以便可以向每個進程發送一個塊。這是基於所有任務花費大約相同時間完成的假設。

在你的情況下,大概這些任務可能需要完全不同的時間。所以有些工作人員在別人之前完成,而這些CPU閒置。如果是這樣的話,那麼這應該按預期工作:

pool.map(launchCmd, clist, chunksize=1) 

效率較低,但它應該是指每個工人得到更多的任務,因爲它完成,直到他們全部完成。

+0

不幸的是,這似乎沒有什麼區別。 – Brian