如何用Python进行并行编程? 对于C++,我们可以使用OpenMP进行并行编程;但是,OpenMP不适用于Python。如果我想并行python程序的某些部分,应该怎么做

如何用Python进行并行编程? 对于C++,我们可以使用OpenMP进行并行编程;但是,OpenMP不适用于Python。如果我想并行python程序的某些部分,应该怎么做,python,parallel-processing,Python,Parallel Processing,本规范的结构可被视为: solve1(A) solve2(B) 其中solve1和solve2是两个独立的函数。如何并行地而不是顺序地运行这类代码以减少运行时间? 代码是: def solve(Q, G, n): i = 0 tol = 10 ** -4 while i < 1000: inneropt, partition, x = setinner(Q, G, n) outeropt = setouter(Q, G, n)

本规范的结构可被视为:

solve1(A)
solve2(B)
其中
solve1
solve2
是两个独立的函数。如何并行地而不是顺序地运行这类代码以减少运行时间? 代码是:

def solve(Q, G, n):
    i = 0
    tol = 10 ** -4

    while i < 1000:
        inneropt, partition, x = setinner(Q, G, n)
        outeropt = setouter(Q, G, n)

        if (outeropt - inneropt) / (1 + abs(outeropt) + abs(inneropt)) < tol:
            break
            
        node1 = partition[0]
        node2 = partition[1]
    
        G = updateGraph(G, node1, node2)

        if i == 999:
            print "Maximum iteration reaches"
    print inneropt
def求解(Q,G,n):
i=0
tol=10**-4
当我<1000时:
inneropt,partition,x=setinner(Q,G,n)
outeropt=setouter(Q,G,n)
如果(外层-内层)/(1+abs(外层)+abs(内层))

其中
setinner
setouter
是两个独立的函数。这就是我想要并行的地方…

CPython使用全局解释器锁,这使得并行编程比C更有趣++

本主题有几个有用的示例和挑战说明:

您可以使用该模块。在这种情况下,我可能会使用一个处理池:

from multiprocessing import Pool
pool = Pool()
result1 = pool.apply_async(solve1, [A])    # evaluate "solve1(A)" asynchronously
result2 = pool.apply_async(solve2, [B])    # evaluate "solve2(B)" asynchronously
answer1 = result1.get(timeout=10)
answer2 = result2.get(timeout=10)
这将产生可以为您做一般工作的流程。由于我们没有通过
进程
,它将为您机器上的每个CPU核心生成一个进程。每个CPU核心可以同时执行一个进程

如果要将列表映射到单个函数,请执行以下操作:

args = [A, B]
results = pool.map(solve1, args)

不要使用线程,因为线程会锁定python对象上的任何操作

这可以非常优雅地使用

要并行化示例,您需要使用
@ray.remote
装饰器定义函数,然后使用
.remote
调用它们

导入光线
ray.init()
#定义函数。
@雷,遥控器
第1(a)条:
返回1
@雷,遥控器
第2(b)段:
返回2
#在后台启动两个任务。
x_id=1.remote(0)
y_id=solve2.远程(1)
#阻止,直到任务完成并获得结果。
x、 y=ray.get([x\u id,y\u id])
与模块相比,此模块有许多优点

  • 同样的代码将运行在多核机器以及机器集群上
  • 进程通过网络高效地共享数据
  • 错误消息被很好地传播
  • 这些函数调用可以组合在一起,例如

    @ray.remote
    def f(x):
    返回x+1
    x_id=f.remote(1)
    y_id=f.remote(x_id)
    z_id=f.remote(y_id)
    ray.get(z#id)#返回4
    
  • 除了远程调用函数外,类还可以远程实例化为

  • 请注意,这是我一直在帮助开发的一个框架。

    正如其他人所说,解决方案是使用多个流程。然而,哪种框架更合适取决于许多因素。除了已经提到的,还有和(我是charm4py的开发者)

    有一种比使用工作池抽象更有效的方法来实现上述示例。在1000次迭代中,主循环将相同的参数(包括完整的图形
    G
    )反复发送给工人。由于至少有一个辅助进程将驻留在不同的进程上,这涉及到复制参数并将其发送到另一个进程。这可能非常昂贵,具体取决于对象的大小。相反,让工作人员存储状态并简单地发送更新的信息是有意义的

    例如,在夏比中,可以这样做:

    class Worker(Chare):
    
        def __init__(self, Q, G, n):
            self.G = G
            ...
    
        def setinner(self, node1, node2):
            self.updateGraph(node1, node2)
            ...
    
    
    def solve(Q, G, n):
        # create 2 workers, each on a different process, passing the initial state
        worker_a = Chare(Worker, onPE=0, args=[Q, G, n])
        worker_b = Chare(Worker, onPE=1, args=[Q, G, n])
        while i < 1000:
            result_a = worker_a.setinner(node1, node2, ret=True)  # execute setinner on worker A
            result_b = worker_b.setouter(node1, node2, ret=True)  # execute setouter on worker B
    
            inneropt, partition, x = result_a.get()  # wait for result from worker A
            outeropt = result_b.get()  # wait for result from worker B
            ...
    
    class Worker(Chare):
    定义初始化(self,Q,G,n):
    self.G=G
    ...
    def SETINERN(自身、节点1、节点2):
    self.updateGraph(节点1、节点2)
    ...
    def解算(Q、G、n):
    #创建两个工人,每个工人在不同的进程上,通过初始状态
    worker_a=Chare(worker,onPE=0,args=[Q,G,n])
    worker_b=Chare(worker,onPE=1,args=[Q,G,n])
    当我<1000时:
    结果_a=辅助对象_a.setinner(节点1、节点2、ret=True)#在辅助对象a上执行setinner
    结果_b=辅助对象_b.setouter(节点1、节点2、ret=True)#在辅助对象b上执行setouter
    inneropt,partition,x=result_a.get()#等待工作进程a的结果
    outeropt=result_b.get()#等待工作程序b的结果
    ...
    
    注意,对于这个例子,我们实际上只需要一个工人。主循环可以执行其中一个函数,并让工人执行另一个函数。但我的代码有助于说明以下几点:

  • 辅助进程A在进程0中运行(与主循环相同)。当
    result\u a.get()
    被阻止等待结果时,工作者a在相同的过程中进行计算
  • 参数会自动通过引用传递给辅助对象A,因为它位于同一位置 过程(不涉及复制)

  • 在某些情况下,可以使用自动并行化循环,尽管它只适用于Python的一小部分:

    from numba import njit, prange
    
    @njit(parallel=True)
    def prange_test(A):
        s = 0
        # Without "parallel=True" in the jit-decorator
        # the prange statement is equivalent to range
        for i in prange(A.shape[0]):
            s += A[i]
        return s
    

    不幸的是,Numba似乎只适用于Numpy数组,而不适用于其他Python对象。从理论上讲,也可能是这样,尽管我还没有尝试过。

    您可以使用
    joblib
    库来执行并行计算和多处理

    from joblib import Parallel, delayed
    
    您只需创建一个要并行运行的函数
    foo
    ,并基于以下代码段实现并行处理:

    output = Parallel(n_jobs=num_cores)(delayed(foo)(i) for i in input)
    
    其中,
    num_core
    可从
    multiprocessing
    库获得,如下所示:

    import multiprocessing
    
    num_cores = multiprocessing.cpu_count()
    
    如果您有一个具有多个输入参数的函数,并且只想通过列表对其中一个参数进行迭代,则可以使用
    functools
    库中的
    partial
    函数,如下所示:

    from joblib import Parallel, delayed
    import multiprocessing
    from functools import partial
    def foo(arg1, arg2, arg3, arg4):
        '''
        body of the function
        '''
        return output
    input = [11,32,44,55,23,0,100,...] # arbitrary list
    num_cores = multiprocessing.cpu_count()
    foo_ = partial(foo, arg2=arg2, arg3=arg3, arg4=arg4)
    # arg1 is being fetched from input list
    output = Parallel(n_jobs=num_cores)(delayed(foo_)(i) for i in input)
    
    您可以通过两个示例找到python和R多处理的完整解释