使用多处理在python中并行化嵌套循环

时间:2017-09-29 13:19:39

标签: python-2.7 parallel-processing

我有一个嵌套循环,给定一个长度为S的长字符串n和一个长度为Q的查询m,检查(天真地)是否{{ 1}}是Q的子字符串,其中包含S个不匹配项。由于外部循环的每次迭代都是独立的,因此将其并行化以加速(对吗?)是有意义的。

例如,如果max_errorS=ATGGTCQ=TCCT,那么max_err=2就是匹配,因为Q中的子字符串TGGT已经S<=2不匹配。但是,如果Q,则max_err=1中的Q不匹配,因为S中没有长度为4的子字符串与S匹配P 1}}不匹配。

<=1

为了并行化,我可以使内部循环成为如下所示的函数。 (我在此函数中移动了def is_match(S,n,Q,m,max_err): # lengths; assume n>m for i in range(0,n-m): cnt = 0 for k in range(m): if S[i+k]!=Q[k]: cnt += 1 if cnt>max_err: break if cnt<=max_err: return i return -1

return -1

现在,我需要并行运行外部循环,收集结果,并检查结果中是否存在非def inner_loop(S,Q,m,i): cnt = 0 for k in range(m): if S[i+k]!=Q[k]: cnt += 1 if cnt>max_err: break if cnt<=max_err: return i return -1 。我被困在这里。以下代码是正确的吗?如何收集结果?

-1

此外,只要上述任何进程返回非def is_match_parallel(S,n,Q,m,max_err): inner_loop_1_par = inner_loop(S=S, Q=Q, m=m, i) result = [] pool = multiprocessing.Pool() ## the following line is not probably right result = pool.map(inner_loop_1_par, range(n-m)) for i in range(n-m): if result[i]!=-1: return i return -1 值,我们就完成了,我们不需要等待其余的进程。反正有吗?

1 个答案:

答案 0 :(得分:1)

您的想法以修改过的形式发挥作用。也就是说,pool.map()必须用更复杂的方法代替,因为您的函数需要的参数多于可迭代参数。此外,使用您的函数依赖于返回值,并且还需要在多处理中进行特殊处理。

以下解决方案使用单独调用的Process对象实例和一个共享变量来指示给定条件是否匹配:

from multiprocessing import Process, Value

def inner_loop(flag,S,Q,m,i,max_err):
    cnt = 0
    if flag.value == -1:
        for k in range(m):
            if S[i+k]!=Q[k]:
                cnt += 1
            if cnt>max_err:
                break
        if cnt<=max_err:
            flag.value = 1

def is_match_parallel(S,n,Q,m,max_err):
    flag = Value('i', -1)
    processes = []
    for i in range(0,n-m):
        p = Process(target=inner_loop, args=(flag,S,Q,m,i,max_err,))
        processes.append(p)
        p.start()
    for p in processes: p.join()
    return flag

此解决方案是用Python 2.7编写的,但在Python 3.X中实现它应该很简单。

is_match_parallel使用特殊的多处理对象flag初始化共享变量Value。默认情况下,该对象应该受到保护,以防止多个线程同时访问它,以便跳过该部分程序。 flag是整数("i")天气指标QS的子字符串。它被初始化为-1,因为只有找到匹配项时,剩余的多处理inner_loop才会将其更改为1。

i范围内的每个n-m启动单独的流程。请注意,对于大范围,您可能需要对此进行基准测试,并确保启动许多过程并不会减慢速度。在这种情况下,您需要将循环拆分为更大的块,这应该不是问题。

p = Process(target=inner_loop, args=(flag,S,Q,m,i,max_err,))使用参数inner_loop将目标函数设置为args,包括共享变量flag。之后,该过程开始。在循环之后,for p in processes: p.join()导致程序在该行上等待,直到所有进程都处理完inner_loop

如果找到匹配项,处理inner_loop的流程会将flag设置为flag.value = 1。如果不是,flag值将保持为-1,表示找不到匹配项。完成所有流程后,is_match_parallel会将当前flag作为Value对象返回(可以通过仅返回flag.value来更改)。

在当前版本的inner_loop中,所有进程都调用inner_loop,但只有当flag仍为-1时,进程才会进入函数的主体 - 带循环。这样,一旦flag变为1,进程将仅通过该函数进行竞争并跳过耗时的部分。

您输入的示例用法是:

s = 'ATGGTC'
q = 'TCCT'

res = is_match_parallel(s, len(s), q, len(q), 2)
print res.value

res = is_match_parallel(s, len(s), q, len(q), 1)
print res.value

分别返回1和-1。