2014-03-26 41 views
3

我有這樣差()

def plotFrame(n): 
    a = data[n, :] 
    do_something_with(a) 

data = loadtxt(filename) 
ids = data[:,0] # some numbers from the first column of data 
map(plotFrame, ids) 

,對我工作的罰款代碼。現在我想嘗試更換map()pool.map()如下:

pools = multiprocessing.Pool(processes=1) 
pools.map(plotFrame, ids) 

但是,這是行不通的,他說:

NameError: global name 'data' is not defined 

的問題是:這是怎麼回事?爲什麼map()不會抱怨data變量沒有傳遞給函數,但pool.map()呢?

編輯: 我正在使用Linux。

編輯2: 基於@Bill的第二個建議,我現在有下面的代碼:

def plotFrame_v2(line): 
    plot_with(line) 

if __name__ == "__main__": 
    ff = np.loadtxt(filename) 
    m = int(max(ff[:,-1])) # max id 
    l = ff.shape[0] 
    nfig = 0 
    pool = Pool(processes=1) 
    for i in range(0, l/m, 50): 
     data = ff[i*m:(i+1)*m, :] # data of one frame contains several ids 
     pool.map(plotFrame_v2, data) 
     nfig += 1   
     plt.savefig("figs_bot/%.3d.png"%nfig) 
     plt.clf() 

按預期工作而已。但是,現在我又有一個意外問題:產生的數字是空白的,而上面的代碼map()產生的數字的內容爲data

+2

你在Windows上運行這個可能嗎?當使用'multiprocessing'時,最好不要依賴全局變量;特別是在Windows上,衍生子進程可能看不到全局變化。 –

+0

這個問題可能會有所幫助,不知道多少關於此,但它可以幫助:http://stackoverflow.com/questions/5442910/python-multiprocessing-pool-map-for-multiple-arguments – ederollora

回答

2

爲避免「意外」問題,請避免使用全局變量。

要與內建map調用plotFrame重現你的第一個代碼示例:

def plotFrame(n): 
    a = data[n, :] 
    do_something_with(a) 

使用multiprocessing.Pool.map,第一件事就是要應對全球data。如果do_something_with(a)也使用一些全局數據,那麼它也應該改變。

要了解如何在numpy的數組傳遞給一個子進程,見Use numpy array in shared memory for multiprocessing。如果您不需要修改數組那麼它就更簡單了:

import numpy as np 

def init(data_): # inherit data 
    global data #NOTE: no other globals in the program 
    data = data_ 

def main(): 
    data = np.loadtxt(filename) 
    ids = data[:,0] # some numbers from the first column of data 
    pool = Pool(initializer=init, initargs=[data]) 
    pool.map(plotFrame, ids) 

if __name__=="__main__": 
    main() 

所有的參數要麼應該作爲參數明確地傳遞給plotFrame或通過init()繼承。

你的第二個代碼示例試圖再次操縱全局數據(通過調用plt):

import matplotlib.pyplot as plt 

#XXX BROKEN, DO NOT USE 
pool.map(plotFrame_v2, data) 
nfig += 1   
plt.savefig("figs_bot/%.3d.png"%nfig) 
plt.clf() 

除非你的主要工序畫點什麼這個代碼可以節省空白的數字。可以在子進程中繪圖或將要繪製的數據明確地發送到父進程,例如,從plotFrame返回並使用pool.map()返回的值。這是一個代碼示例:how to plot in child processes

4

使用multiprocessing.pool,您正在生成單個進程以使用共享(全局)資源data。通常,您可以通過明確地使該資源global允許進程與父進程中的共享資源一起使用。但是,最好的做法是將所有需要的資源顯式作爲函數參數傳遞給子進程。如果您在使用Windows,則需要。檢查出multiprocessing guidelines here

所以,你可以嘗試做

data = loadtxt(filename) 

def plotFrame(n): 
    global data 
    a = data[n, :] 
    do_something_with(a) 

ids = data[:,0] # some numbers from the first column of data 
pools = multiprocessing.Pool(processes=1) 
pools.map(plotFrame, ids) 

甚至更​​好看this thread的餵養多個參數的函數與multiprocessing.pool。一個簡單的方法可能是

def plotFrameWrapper(args): 
    return plotFrame(*args) 

def plotFrame(n, data): 
    a = data[n, :] 
    do_something_with(a) 

if __name__ == "__main__": 
    from multiprocessing import Pool 
    data = loadtxt(filename) 
    pools = Pool(1) 

    ids = data[:,0] 
    pools.map(plotFrameWrapper, zip([data]*len(inds), inds)) 
    print results 

最後一兩件事:因爲它看起來像你從你的例子做的是切片陣列的唯一的東西,你可以簡單地切先再通過切片陣列的功能:

def plotFrame(sliced_data): 
    do_something_with(sliced_data) 

if __name__ == "__main__": 
    from multiprocessing import Pool 
    data = loadtxt(filename) 
    pools = Pool(1) 

    ids = data[:,0] 
    pools.map(plotFrame, data[ids]) 
    print results 
+0

pools.map(zip([數據] * len(inds),inds))你的意思是:pools.map(plotFrameWrapper,zip([data] * len(inds),inds)),我猜。這個解決方案很好。謝謝。但是,我不明白你的第二個建議。原則上,我現在正在做的是將數據幀化。然後用map()處理切片數組。 – Tengis

+0

是的,在'zip'部分很好的捕捉。至於第二個建議,numpy數組是可迭代的,如果你說'for 2d_array',每個''x代表一行。所以,如果你在framewise中切分數據,然後將其輸入到map中,map將遍歷切片數組的行。 – wflynny