在多处理中更新列表字典

时间:2019-10-23 20:41:48

标签: python performance dictionary multiprocessing

我想计算将列表中所有可能的对分开的元素的平均数量。以下脚本效果很好

from itertools import combinations
from operator import itemgetter
from collections import defaultdict

lst = [['A','D','B',],['A','M','N','B'],['A','C','B']]
elms = set(x for l in lst for x in l)

def test1():
    d = defaultdict(list)
    for i in lst:
        combs = list(combinations(i, 2))
        combs_sorted = [sorted(i) for i in combs]
        for j in combs_sorted:
            a = i.index(j[0])
            b = i.index(j[1])
            d[tuple(j)].append(abs((a+1)-b))
    return(d)

d = test1()
d = {k: sum(v)/len(v) for k, v in d.items()}
for k,v in d.items():
    print(k,v)

结果就是期望的结果。

('A', 'D') 0.0
('A', 'B') 1.3333333333333333
('B', 'D') 2.0
('A', 'M') 0.0
('A', 'N') 1.0
('M', 'N') 0.0
('B', 'M') 3.0
('B', 'N') 2.0
('A', 'C') 0.0
('B', 'C') 2.0

但是,当列表和元素的数量大大增加时,该脚本会变得非常慢。我尝试在this answer

之后使用多处理
import multiprocess as mp

def init2(child_conn):
    d = defaultdict(list)
    for i in lst:
        combs = list(combinations(i, 2))
        combs_sorted = [sorted(i) for i in combs]
        for j in combs_sorted:
            a = i.index(j[0])
            b = i.index(j[1])
            d[tuple(j)].append(abs((a+1)-b))
    child_conn.send(d)

def test2():
    parent_conn, child_conn = mp.Pipe(duplex=False)
    p = mp.Process(target=init2, args=(child_conn,))
    p.start()
    d = parent_conn.recv()
    p.join()
    return(d)

d = test1()
d = {k: sum(v)/len(v) for k, v in d.items()}
for k,v in d.items():
    print(k,v)

但是此脚本似乎比上一个脚本还要慢。

import time

t = time.process_time()
test1()
print(time.process_time() - t)

6.0000000000004494e-05

t = time.process_time()
test2()
print(time.process_time() - t)

0.017596

如何加快计算速度?

1 个答案:

答案 0 :(得分:0)

  1. 除非只是用于说明玩具的示例,否则我想知道为什么您不愿意加快60usec的计算速度。
  2. 您只打开一个子进程即可完成所有工作,因此不应期望性能提高。
  3. 即使您打开的数量更多,与计算中的60微秒相比,打开多进程+ Pipe的开销也要大得多。

  4. 在以下情况下使用多重处理有效:

  5. 您的基本计算比mp开销慢得多。
  6. 当您有一个预先创建的工作池时,等待通信进行一些计算。使用这种配置(通常在服务器上可以找到),您只需支付通信费用(顺便说一句,这比60个使用时间还长)。

因此,在底线中,为了进行如此短的计算,只需执行一个过程即可。