如何在python中使用多处理

如何在python中使用多处理,python,multiprocessing,Python,Multiprocessing,我是python新手,我想在下面的代码中进行并行编程,并希望使用python中的多处理来实现。那么如何修改代码呢?我一直在使用Pool搜索这个方法,但发现我可以遵循的示例有限。有人能帮我吗?多谢各位 请注意,setinner和setouter是两个独立的函数,因此我希望使用并行编程来减少运行时间 def solve(Q,G,n): i = 0 tol = 10**-4 while i < 1000: inneropt,partition,x =

我是python新手,我想在下面的代码中进行并行编程,并希望使用python中的多处理来实现。那么如何修改代码呢?我一直在使用Pool搜索这个方法,但发现我可以遵循的示例有限。有人能帮我吗?多谢各位

请注意,setinner和setouter是两个独立的函数,因此我希望使用并行编程来减少运行时间

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
是非变异函数;如果不是这样,事情会更复杂

第一步是决定你想同时做什么


一件显而易见的事情是同时执行
setinner
setouter
。它们彼此完全独立,并且总是需要同时完成。所以,这就是我要做的。而不是这样做:

inneropt,partition,x = setinner(Q,G,n)
outeropt = setouter(Q,G,n)
…我们希望将这两个函数作为任务提交到池中,然后等待这两个函数都完成,然后获取这两个函数的结果

concurrent.futures
模块(在Python2.x中需要一个第三方后台端口)比
多处理模块(在2.6+中的stdlib中)更容易执行“等待两者都完成”之类的操作,但在这种情况下,我们不需要任何花哨的东西;如果其中一个提前完成,我们就没有什么事情要做,直到另一个完成为止。所以,让我们继续:

当然,你可以让这个更漂亮

例如,假设您很少需要超过几百次迭代,因此总是计算1000次迭代是浪费的。您可以在启动时推送第一个N,然后在循环中每次推送一个(或者每N次再推N个),这样您就不会进行超过N次浪费的迭代。您无法在完美并行性和最小浪费之间获得理想的折衷,但您通常可以很好地调整它


此外,如果任务实际上不需要那么长的时间,但是您有很多任务,那么您可能需要对它们进行批处理。一个非常简单的方法是使用一个
map
变量,而不是
apply_async
;这可能会使您的获取代码稍微复杂一些,但它会使排队和批处理代码变得非常简单(例如,在
chunksize
为10的100个参数列表上映射每个
func
只不过是两行简单的代码)。

该代码缩进不正确,并且会出现sytax错误。你能纠正你的代码吗?顺便说一句,这段代码可能使用了一些矩阵或图形库,这些矩阵或图形库可能是作为C扩展模块构建的,并且可能在不持有GIL(如NumPy)的情况下运行缓慢的操作,因此你可以只使用
线程化
而不是
多处理
,或者甚至在相关的情况下进行自动数据并行(如SciPy或KDT的某些部分,如果您正确配置和安装了先决条件),在这种情况下,
多处理
实际上会降低您的速度…3个函数(setInner、setouter、updateGraph)的相对运行时间是多少?
Q,G,n
对象大吗?你会在每次迭代中更新几乎所有的值(我假设它们是复合对象)还是只更新其中的一小部分?对于一些明确定义的用例,比如将两个函数设置为异步运行,lelo helper包是有用的-(在这种情况下,它可能只需要修饰setinner和setoutter即可):@jsbueno:看起来很酷。我担心Python中的自动惰性对象,因为实际上不可能覆盖Python中所有有用的表达式,因此最终可能会得到
minval
而不是实际计算结果。(在C++中,这不是问题,因为(a)在您可以过载的事情中,分配、复制和转换为<代码> t& < /COD>,并且(b)静态类型通常以Python不能的方式强制严格,但是它显然会在OP的情况下工作,因为他立即解包一个,并将另一个传递给
abs
…@jsbueno:事实上,经过再三考虑……在OP的情况下,将第一个结果解包为三个变量显然会受阻,这意味着他需要以与我的回答相同的方式重写代码(执行操作,然后获得结果),以实际获得任何并行性。尽管仅仅撤销这两个调用将是一个快速而肮脏的解决办法。@abanert-我不同意不能覆盖所有有用的表达式。包“lelo”可能包含错误,但要在Python中使用值,必须通过“dunder”(
\uuuu NAME\uuu
)方法之一。纯assignemnt是不可重写的,但assignment所做的只是将惰性对象本身绑定到另一个名称。当它被打印、比较、序列化时,必须获取它的值。
pool = multiprocessing.Pool(2) # we never have more than 2 tasks to run
while i < 1000:
    # parallelly start both tasks
    inner_result = pool.apply_async(setinner, (Q, G, n))
    outer_result = pool.apply_async(setouter, (Q, G, n))

    # sequentially wait for both tasks to finish and get their results
    inneropt,partition,x = inner_result.get()
    outeropt = outer_result.get()

    # the rest of your loop is unchanged
pool = multiprocessing.Pool() # let it default to the number of cores
inner_results = []
outer_results = []
for _ in range(1000):
    inner_results.append(pool.apply_async(setinner, (Q,G,n,i))
    outer_results.append(pool.apply_async(setouter, (Q,G,n,i))
while i < 1000:
    inneropt,partition,x = inner_results.pop(0).get()
    outeropt = outer_results.pop(0).get()
    # result of your loop is the same as before