2010-11-07 12 views
2

我一直在努力想辦法讓下面這段代碼執行速度更快:線程快速創建大量的圖表

def do_chart(target="IMG_BACK", xlabel="xlabel", ylabel="ylabel", title="title",  ydata=pylab.arange(1961, 2031, 1)): 
    global MYRAMDICT 
    MYRAMDICT = {} 
    print "here" 
    for i in range(70): 
     MYRAMDICT[i] = cStringIO.StringIO() 
     xdata = pylab.arange(1961, 2031, 1) 
     pylab.figure(num=None, figsize=(10.24, 5.12), dpi=1, facecolor='w', edgecolor='k') 
     pylab.plot(xdata, ydata, linewidth=3.0) 
     pylab.xlabel(xlabel); pylab.ylabel(ylabel); pylab.title(i) 
     pylab.grid(True) 
     pylab.savefig(MYRAMDICT[i], format='png') 
     pylab.close() 

此功能(請忽略pylab命令,他們在這裏只是爲插圖)創建一個字典(MYTAMDICT),我用cString對象填充,用於將圖表存儲在內存中。這些圖表稍後會動態呈現給用戶。

有人請幫我利用線程,以便我可以使用我的所有內核,並使此功能更快地執行?或者指出我想改進它的想法?

+0

什麼是當前的性能和它需要多快? – 2010-11-07 20:19:27

+0

#Steven:如果我在for循環的開頭插入「print i」,則可以看到每個圖像需要接近一秒。但是,當我擁有真正應該使用的pylab代碼時,這個時間會增加。每次用戶更改新數據庫時都會運行此函數,因此它會經常更改。我知道我可以繪製第一幅圖像,而另一幅則在後臺完成,但我的線程聽起來像是最好的解決方案。 – relima 2010-11-07 20:23:09

回答

3

對於說明,你會好得多使用多線程比...你有一個「易並行」的問題,並沒有磁盤IO約束(你寫存儲器)。當然,經過大量的東西來回的過程之間將得到昂貴,但返回代表巴紐字符串應該不會太差..

它可以很簡單地完成:

import multiprocessing 
import cStringIO 

import matplotlib.pyplot as plt 
import numpy as np 

import itertools 

def main(): 
    """Generates 1000 random plots and saves them as .png's in RAM""" 
    pool = multiprocessing.Pool() 
    same_title = itertools.repeat('Plot %i') 
    fig_files = pool.map(plot, itertools.izip(xrange(1000), same_title)) 

def plot(args): 
    """Make a random plot""" 
    # Unfortunately, pool.map (and imap) only support a single argument to 
    # the function, so you'll have to unpack a tuple of arguments... 
    i, titlestring = args 

    outfile = cStringIO.StringIO() 

    x = np.cumsum(np.random.random(100) - 0.5) 

    fig = plt.figure() 
    plt.plot(x) 
    fig.savefig(outfile, format='png', bbox_inches='tight') 
    plt.title(titlestring % i) 
    plt.close() 

    # cStringIO files aren't pickelable, so we'll return the string instead... 
    outfile.seek(0) 
    return outfile.read() 

main() 

不使用多,這在我的機器上需要約250秒。多處理(8核),需要約40秒。

希望能有所幫助...

+0

這很酷。感謝您的幫助。但我有一個問題要問你。我爲python 2.4安裝了一個多處理的backport,但是當我使用你的代碼時,我得到: ****************************** ************************* **正在載入-c ****************** ************************************************** *** 回溯(最近呼叫最後): 文件「」,第11行,在? IOError:[Errno 2]沒有這樣的文件或目錄:'-c' **加載時間:0.00秒 **警告:腳本中有錯誤,請按任意鍵退出 想法? 非常感謝您的幫助。 – relima 2010-11-08 00:15:38

+0

@relima - 呃...我猜這是2.4上的多處理問題...無論如何,事情在2.6和2.7上似乎都可以正常工作......恐怕我沒有比這更好的想法,儘管...... – 2010-11-08 15:27:26

2

當且僅當pylab在執行時釋放gil時,線程纔會幫助你。
此外,pylib必須是線程安全的,並且您的代碼必須以線程安全的方式使用它,這可能並非總是如此。

這就是說,如果你打算使用線程,我認爲這是一個經典的工作隊列的情況;因此,我會使用queue object,這足以處理這種模式。

下面是我剛剛通過干涉您的代碼和隊列文檔中給出的示例推出的一個示例。我甚至沒有徹底檢查過它,所以它會有錯誤;它比其他任何東西都更有意義。

# "Business" code 
def do_chart(target="IMG_BACK", xlabel="xlabel", ylabel="ylabel", title="title",  ydata=pylab.arange(1961, 2031, 1)): 
    global MYRAMDICT 
    MYRAMDICT = {} 
    print "here" 
    for i in range(70): 
     q.put(i) 
    q.join()  # block until all tasks are done 

def do_work(i): 
    MYRAMDICT[i] = cStringIO.StringIO() 
    xdata = pylab.arange(1961, 2031, 1) 
    pylab.figure(num=None, figsize=(10.24, 5.12), dpi=1, facecolor='w', edgecolor='k') 
    pylab.plot(xdata, ydata, linewidth=3.0) 
    pylab.xlabel(xlabel); pylab.ylabel(ylabel); pylab.title(i) 
    pylab.grid(True) 
    pylab.savefig(MYRAMDICT[i], format='png') 
    pylab.close() 


# Handling the queue 
def worker(): 
    while True: 
     i = q.get() 
     do_work(i) 
     q.task_done() 

q = Queue() 
for i in range(num_worker_threads): 
    t = Thread(target=worker) 
    t.daemon = True 
    t.start()