如何以递归方式维护池中的全局进程?

时间:2018-03-09 12:55:28

标签: python python-3.x parallel-processing python-multiprocessing python-pool

我想实现一个递归并行算法,我希望只创建一次池,每次执行一个作业等待所有作业完成,然后再次使用先前输出的输入调用进程,然后再次在下一个时间步骤等同等。

我的问题是我已经实现了一个版本,其中每次创建并杀死池的步骤,但这非常慢,甚至比顺序版本慢。当我尝试实现一个只在开始时创建池的版本时,当我尝试调用join()时出现断言错误。

这是我的代码

def log_result(result):

    tempx , tempb, u = result

    X[:,u,np.newaxis], b[:,u,np.newaxis] = tempx , tempb


workers =  mp.Pool(processes = 4) 
for t in range(p,T):

    count = 0 #==========This is only master's job=============
    for l in range(p):
        for k in range(4):
            gn[count]=train[t-l-1,k]
            count+=1
    G = G*v +  gn @ gn.T#==================================

    if __name__ == '__main__':
        for i in range(4):
            workers.apply_async(OULtraining, args=(train[t,i], X[:,i,np.newaxis], b[:,i,np.newaxis], i, gn), callback = log_result)


        workers.join()   

X和b是我想直接在主存储器中更新的矩阵。

这里有什么问题,我得到断言错误?

我可以在池中实现我想要的内容吗?

1 个答案:

答案 0 :(得分:1)

您无法加入未先关闭的池,因为join()将等待工作进程终止,而不是要完成的作业(https://docs.python.org/3.6/library/multiprocessing.html第17.2.2.9节)。

但是因为这将关闭池,这不是你想要的,你不能使用它。所以加入已经结束,你需要实施一个"等待所有工作完成"靠自己。

在没有繁忙循环的情况下执行此操作的一种方法是使用队列。您也可以使用有界信号量,但它们不适用于所有操作系统。

counter = 0
lock_queue = multiprocessing.Queue()
counter_lock = multiprocessing.Lock()

def log_result(result):

    tempx , tempb, u = result

    X[:,u,np.newaxis], b[:,u,np.newaxis] = tempx , tempb
    with counter_lock:
        counter += 1
        if counter == 4:
            counter = 0
            lock_queue.put(42)



workers =  mp.Pool(processes = 4) 
for t in range(p,T):

    count = 0 #==========This is only master's job=============
    for l in range(p):
        for k in range(4):
            gn[count]=train[t-l-1,k]
            count+=1
    G = G*v +  gn @ gn.T#==================================

    if __name__ == '__main__':
        counter = 0
        for i in range(4):
            workers.apply_async(OULtraining, args=(train[t,i], X[:,i,np.newaxis], b[:,i,np.newaxis], i, gn), callback = log_result)


        lock_queue.get(block=True)

这会在提交作业之前重置全局计数器。作业完成后,您将回调增加全局计数器。当计数器达到4(您的工作数)时,回调知道它已经处理了最后的结果。然后在队列中发送虚拟消息。您的主程序正在Queue.get()等待某些内容出现在那里。

这允许您的主程序在所有作业完成之前阻止,而不关闭池。

如果您使用multiprocessing.Pool中的ProcessPoolExecutor替换concurrent.futures,则可以跳过此部分并使用

concurrent.futures.wait(fs, timeout=None, return_when=ALL_COMPLETED)

阻止,直到所有提交的任务都完成。从功能的角度来看,这些之间没有区别。 concurrent.futures方法的行数较短,但结果完全相同。