将子集从大型数据库定向到python

时间:2016-05-12 20:27:07

标签: python parallel-processing multiprocessing

我编写了一些Python代码,用于从大型数据库中提取信息,对数据库中的每个项目执行一些最大似然建模,然后存储结果。代码可以串行工作,每个项目需要1-2秒。问题是,我在数据库中有几百万个项目,因此代码的连续运行将花费数周时间。我可以访问一个拥有16个cpu的群集,并且我已经编写了一个功能,可以将初始输入目录分成"块,"在每个块上运行建模代码,然后组织结果。由于代码建模部分的复杂性及其对第三方python软件的依赖,我一直在尝试使用多处理来并行化这些代码,以便输入目录的每个块都在一个单独的cpu上运行。目前,我尝试产生的进程只能在一个cpu上运行。有谁知道如何解决这一问题?我是一名自学成才的科学程序员,所以我有一些使用Python的经验,尽管这是我第一次尝试并行化。代码太长了,不能完整地显示在这里,但它基本上做了以下几点:

def split(a, n):
    k, m = len(a) / n, len(a) % n
    return (a[i * k + min(i, m):(i + 1) * k + min(i + 1, m)] for i in xrange(n))

ncpus = mp.cpu_count()
chunks = list(split(catlist, ncpus))
images = [im1, im2, im3, im4, im5, im6, im7, im8, im9, im10, im11, im12]

def process_chunks(chunk):
    database_chunk = database[chunk[:]]
    for i in range(0,len(database_chunk)):
        # perform some analysis
        for j in range(0,len(images)):
            # perform more analysis      
    my_dict = {'out1': out1, 'out2':out2, 'out3': out3}
    return my_dict

pool = mp.Pool(processes=ncpus)
result = [pool.apply(process_chunks, args=(chunks[id],)) for id in range(0,len(chunks))]

对于数据库中只有13个项目的简单测试示例,这就是块的样子(大致均匀分割列表的列表):

chunks = [[0,1,2,3],[4,5,6],[7,8,9],[10,11,12]]

代码运行正常,pool.apply命令生成多个进程,但所有进程都在单个cpu上运行,并且运行时没有串行改进(实际上它有点慢,我想到期了)生成每个进程的开销)。有没有办法强制将每个进程分配给一个单独的cpu,所以当我将它应用于完整数据库(有数百万项)时,我得到了一些改进?或者也许是更好的解决这个问题的方法吗?

提前非常感谢!

注意:如果它进一步澄清情况,我是一名天文学家,数据库是一个包含超过一百万条目的大型源目录,图像是12个不同波段的宽场马赛克,而我是&#39 ; m对每个源的每个波段进行最大似然测光。

1 个答案:

答案 0 :(得分:0)

我一开始以为你遇到了全局解释器锁,但是你已经使用multiprocessing躲过了。值得庆幸的是,这意味着事情要比其他方面容易得多。来自the docs

  

apply()内置函数的等效项。 阻塞直到结果准备好,因此apply_async()更适合并行执行工作。

(强调我的)

apply_async()的API与apply()略有不同,但这是一个非常简单的修改:

calculations = []

def reaper(result):
    calculations.append(result)

for id in range(0, len(chunks)):
    pool.apply_async(process_chunks, args=(chunks[id],), callback=reaper)