在python-3.5中死亡多处理的未知原因

时间:2016-10-05 15:22:34

标签: python multiprocessing python-3.5

我有一个数据框df包含二十万件物品的信息。现在我想测量它们的成对相似性,并选择最高n对。这意味着,我应该计算近数十亿计算。鉴于巨大的计算成本,我选择通过多处理来运行它。这是我到目前为止编写的代码:

user_list = (list(range(1, 200001))
def gen_pair():
    for u1 in reversed(user_list):
        for u2 in reversed(list(range(1, u1))):
            yield (u1, u2)

def cal_sim(u_pair):
    u1, u2 = u_pair
    # do sth quite complex...
    sim = sim_f(df[u1], df[u2])
    if sim < 0.5:
        return None
    else:
        return (u1, u2, sim)

with multiprocessing.Pool(processes=3) as pool:
    vals = pool.map(cal_sim, gen_pair())
    for v in vals:
        if v is not None:
            with open('result.txt', 'a') as f:
                f.write('{0}\t{1}\t{2}\n'.format(v[0], v[1], v[2]))

当我刚拿到前1000名用户时,它的效果非常好。但是,当我把它们全部拿走时,它在result.txt中已经死了,没有一个单词。但是如果我添加进程的数量,它也会死掉。我想知道是什么原因,我该如何解决?提前谢谢。

编辑:

以下是我的sim_f代码:

def sim_f(t1, t2):
    def intersec_f(l1, l2):
        return set(l1)&set(l2)

    def union_f(l1, l2):
        return set(l1)|set(l2)

    a_arr1, a_arr2 = t1[0], t1[1]
    b_arr1, b_arr2 = t2[0], t2[1]
    sim =  float(len(union_f(intersec_f(a_arr1, a_arr2), intersec_f(b_arr1, b_arr2))))\
        / float(len(union_f(union_f(a_arr1, a_arr2), union_f(b_arr1, b_arr2))))
    return sim

1 个答案:

答案 0 :(得分:2)

没什么可继续的,但请尝试:

vals = pool.imap(cal_sim, gen_pair())
            ^

相反:请注意我将“map”更改为“imap”。如上所述,map()阻塞,直到整个计算完成,因此在完成所有工作之前,您永远不会进入for循环。 imap会立即“返回”。

如果您不关心交付结果的顺序,请改用imap_unordered()

打开文件

关于评论中提出的问题:

with open('result.txt', 'w') as f:
    for v in vals:
        if v is not None:
            f.write('{0}\t{1}\t{2}\n'.format(v[0], v[1], v[2]))

是打开文件一次的明显方法。但是如果它对你有所帮助我会感到惊讶 - 迄今为止的所有证据都表明cal_sim()只是昂贵的。

加速SIM_F

正在进行大量冗余工作:

def sim_f(t1, t2):
    def intersec_f(l1, l2):
        return set(l1)&set(l2)

    def union_f(l1, l2):
        return set(l1)|set(l2)

    a_arr1, a_arr2 = t1[0], t1[1]
    b_arr1, b_arr2 = t2[0], t2[1]
    sim =  float(len(union_f(intersec_f(a_arr1, a_arr2), intersec_f(b_arr1, b_arr2))))\
    / float(len(union_f(union_f(a_arr1, a_arr2), union_f(b_arr1, b_arr2))))
    return sim

完全未经测试,这是显而易见的;-)重写:

def sim_f(t1, t2):
    a1, a2 = set(t1[0]), set(t1[1])
    b1, b2 = set(t2[0]), set(t2[1])
    sim =  float(len((a1 & a2) | (b1 & b2))) \
            / len((a1 | a2) | (b1 | b2))
    return sim

这更快,因为:

  • 每次输入只转换为一次设置。
  • 没有任何无用(但非常耗时)的集合的转换。
  • 对于工会和十字路口没有内部函数调用开销。
  • 消除了对float()的一次不必要的调用(或者,在Python 3中,剩余的float()调用也可以被删除)。