2010-11-07 28 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()