函数内部的并行性?

时间:2016-09-22 14:22:46

标签: python multithreading list parallel-processing

我有一个功能可以计算项目列表在rows下方显示的频率:

def count(pair_list):
    return float(sum([1 for row in rows if all(item in row.split() for item in pair_list)]))

if __name__ == "__main__":
    pairs = [['apple', 'banana'], ['cookie', 'popsicle'], ['candy', 'cookie'], ...]
    # grocery transaction data
    rows = ['apple cookie banana popsicle wafer', 'almond milk eggs butter bread', 'bread almonds apple', 'cookie candy popsicle pop', ...]

    res = [count(pair) for pair in pairs]

实际上,len(rows)1000018000中有pairs个元素,因此count()中列表理解的计算成本与在主要功能是昂贵的。

我尝试了一些并行处理:

from multiprocessing.dummy import Pool as ThreadPool
import multiprocessing as mp

threadpool = ThreadPool(processes = mp.cpu_count())

res = threadpool.map(count, pairs)

这也不会很快。事实上,15分钟后,我就放弃了工作,因为它看起来并没有结束。两个问题:1)如何加快count()中的实际搜索速度? 2)如何检查threadpool.map进程的状态(即查看剩下多少对进行迭代)?

1 个答案:

答案 0 :(得分:1)

1)计算的总体复杂性是巨大的,它来自不同的来源:

a)您在低级别的计算中拆分行,因此python必须为每次迭代创建新的行拆分。为避免这种情况,您可以预先计算行数。这样的事情将完成这项工作(“计数”功能的微小变化):

rows2 = [row.split() for row in rows]

b)您逐个比较列表项,即使您只需要检查另一个列表中是否存在单词。在这里我们可以更多地调整它(并在“count”函数中使用rows3而不是rows2):

rows3 = [set(row.split()) for row in rows]

def count(pair_list):
    return float(sum([1 for row in rows3 if all(item in row for item in pair_list)]))

c)用行中的每个单词成对检查每个单词。对于原始版本,每次调用“count”函数时,计算需要2 * len(行)* len(行)次迭代,而它可能需要更少。对于选项b),在良好的情况下,它可以降至2 * len(行),但是每对可以进行一次设置查找,而不是2。 诀窍是为每一行准备所有可能的单词*单词组合,并检查该集合中是否存在相应的单词元组。 因此,在main函数中,您可以创建复杂的不可变搜索结构:

rows4 = [set((a, b) for a in row for b in row) for row in rows2]

现在“count”看起来会有所不同,需要使用tuple而不是list:

def count2(pair):
    return float(len([1 for row in rows4 if(pair in row)]))

所以你称之为有点不同:     res = [count2(元组(对))对成对]

请注意,搜索结构创建在时间和空间上每行采用len(row.split())^ 2,因此如果您的行可能很长,则不是最佳。毕竟,选项b)可以更好。

2)你可以预测“计数”的呼叫次数 - 它是len(对)。计算“计数”功能的调用并在其中进行调试打印,例如每1000次调用。