简体   繁体   English

多处理 - 将工作发送给工人,接收结果,更新工人,重新计算

[英]Multiprocessing - send job to workers, receive results, update workers, recompute

I am trying to spawn workers, give them some tasks, send results back to the main process which processes the results, update all the workers with new information and send them more tasks. 我试图产生工人,给他们一些任务,将结果发送回处理结果的主流程,用新信息更新所有工人并向他们发送更多任务。 I want to do this a certain amount of iterations before ending the workers. 我想在结束工作之前做一定数量的迭代。

My code seems to be working fine, but not all the workers are beeing updated for each iteration. 我的代码似乎工作正常,但并非所有工作人员都在为每次迭代更新。 Eg an output I received was: 例如,我收到的输出是:

Creating  4  workers
Finished workin 4
Finished workin 6
Finished workin 3
Finished workin 4

According to the Pipe Documentation recv() should block until there is something to receive. 根据管道文档, recv()应该阻塞,直到有东西要收到。 Why is this not the case in my example? 为什么在我的例子中不是这种情况?

from multiprocessing import Process, Queue, JoinableQueue, Pipe, Event, Barrier, Value
import time

def worker(qu_task,qu_results,chi,ev,bar,val):
    ext=False
    dum=0
    while True:
        ev.wait()
        while qu_task.empty() is False:
            a=qu_task.get() # Pop work from queue
            if a is None: #Poison pill
                bar.wait() # Wait for all processes so that they all receive "None"
                ext=True
                qu_task.task_done() #
                print("Finished workin", dum)
                break

            # Do stuff
            time.sleep(.1)
            qu_results.put(111)
            qu_task.task_done()

#        time.sleep(1.0)

        if ext: # Break out if finished
            break

        data1, data2  = chi.recv() # Blocks until there its something to receive
        dum+=data2
        # Do stuff

def main(NProc, NScen, NTime, branch):
    qu_tasks=JoinableQueue() # To use task_done() and join()
    qu_results=Queue()
    workers=[]
    val=Value('i',0)
    conn=[]
    bar=Barrier(NProc)
    ev=Event()
    print("Creating ", NProc, " workers")
    for i in range(NProc):
        par,chi=Pipe()
        workers.append(Process(target=worker,args=(qu_tasks,qu_results,chi,ev,bar,val)))
        conn.append(par)

    for w in workers:
        w.start()

    for t in reversed(range(NTime)):
        for s in range(NScen):
            a=0.0
            for b in branch:
                k=(b,s,t)
                qu_tasks.put(k) # Send work

            ev.set() # Start workers
            qu_tasks.join() # Synchronize workers
            ev.clear() # Reset lock
            for idx,i in enumerate(branch):
                a+=qu_results.get()
            #print(a)

            kk=[1,2,3,5]
            for idx,c in enumerate(conn):
                c.send(([i*(1+idx) for i in kk],1)) # Send more data to workers

    for i in range(NProc): # Kill workers
        qu_tasks.put(None)
    ev.set()
    qu_tasks.join()

    for w in workers: # Wait for them to finish
        w.join()

if __name__=="__main__":
    branch=[i for i in range(1,7)]
    NTime=2
    NScen=3

    main(4,NScen, NTime, branch)

Pipe.recv() waits, do not worry about that. Pipe.recv()等待,不用担心。 It just does not get invoked 6 times, as the loop bails out sooner because of the None . 它只是没有被调用6次,因为循环因为None而更快失效。

Remember that asynchronous programming is well, asynchronous, and there is such schedule of your communication+processing pattern when a worker starts consuming messages from the "next" batch without reaching Pipe.recv() 请记住,异步编程是完全异步的,当工作人员开始使用“下一个”批处理中的消息而没有到达Pipe.recv()时,会有这样的通信+处理模式的时间表。

If you move that time.sleep(.1) around, you can reach "Finished workin 0" too. 如果你移动那个time.sleep(.1) ,你也可以达到“完成工作0”。

Also, if you slow down the (Joinable)Queue.put() loop, you can reach a situation when the task queue temporarily gets empty mid-loop, sooner than you have dispatched all the tasks, so the workers will reach the Pipe.recv() , but the main program will wait on the JoinableQueue.join() 此外,如果您减慢(Joinable)Queue.put()循环,您可以在任务队列在循环中暂时(Joinable)Queue.put()空时达到一种情况,比您调度所有任务更快,因此工作人员将到达Pipe.recv() ,但主程序将等待JoinableQueue.join()

Suggestion: pick either pipes or (joinable)queues, but do not pick both. 建议:选择管道或(可加入)队列,但不要选择两者。 Interlocking them is just hard, and brings no benefit. 联锁它们很难,并没有带来任何好处。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM