如何用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的结果
...
注意,对于这个例子,我们实际上只需要一个工人。主循环可以执行其中一个函数,并让工人执行另一个函数。但我的代码有助于说明以下几点:
result\u a.get()
被阻止等待结果时,工作者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多处理的完整解释