假设我收集了Process
- es,a[0]
到a[m]
。
然后,这些流程会通过队列将作业发送到另一个Process
- es,b[0]
到b[n]
的集合,其中m > n
或者,图表:
a[0], a[1], ..., a[m] ---Queue---> b[0], b[1], ..., b[n]
现在,如何将b
流程的结果返回到相关的a
流程?
我的第一个猜测是使用multiprocessing.Pipe()
所以,我尝试过以下几点:
## On the 'a' side
pipe = multiprocessing.Pipe()
job['pipe'] = pipe
queue.put(job)
rslt = pipe[0].recv()
## On the 'b' side
job = queue.get()
... process the job ...
pipe = job['pipe']
pipe.send(result)
并且它不适用于错误:Required argument 'handle' (pos 1) not found
阅读了许多文档,我提出了:
## On the 'a' side
pipe = multiprocessing.Pipe()
job['pipe'] = multiprocessing.reduction.reduce_connection(pipe[1])
queue.put(job)
rslt = pipe[0].recv()
## On the 'b' side
job = queue.get()
... process the job ...
pipe = multiprocessing.reduction.rebuild_connection(job['pipe'], True, True)
pipe.send(result)
现在我收到了另一个错误:ValueError: need more than 2 values to unpack
。
我尝试过搜索和搜索,但仍无法找到如何正确使用reduce_
和rebuild_
方法。
请帮助,以便我可以将b
的值返回到a
。
答案 0 :(得分:2)
我建议避免使用Pipe和文件描述符的这种移动(上次我尝试过,它不是很标准,也没有很好地记录)。不得不处理它是一种痛苦,我不推荐它: - /
我建议采用不同的方法:让main
管理连接。保留工作队列,但是以不同的路径发送响应。这意味着您需要某种线程标识符。我将提供玩具实施来说明我的建议:
#!/usr/bin/env python
import multiprocessing
import random
def fib(n):
"Slow fibonacci implementation because why not"
if n < 2:
return n
return fib(n-2) + fib(n-1)
def process_b(queue_in, queue_out):
print "Starting process B"
while True:
j = queue_in.get()
print "Job: %d" % j["val"]
j["result"] = fib(j["val"])
queue_out.put(j)
def process_a(index, pipe_end, queue):
print "Starting process A"
value = random.randint(5, 50)
j = {
"a_id": index,
"val": value,
}
queue.put(j)
r = pipe_end.recv()
print "Process A sent value %d and received: %s" % (value, r)
def main():
print "Starting main"
a_pipes = list()
jobs = multiprocessing.Queue()
done_jobs = multiprocessing.Queue()
for i in range(5):
multiprocessing.Process(target=process_b, args=(jobs, done_jobs,)).start()
for i in range(10):
receiver, sender = multiprocessing.Pipe(duplex=False)
a_pipes.append(sender)
multiprocessing.Process(target=process_a, args=(i, receiver, jobs)).start()
while True:
j = done_jobs.get()
a_pipes[j["a_id"]].send(j["result"])
if __name__ == "__main__":
main()
请注意,作业队列直接连接在a
和b
进程之间。 a
进程负责放置其标识符(“主人”应该知道)。 b
使用不同的队列完成工作。我使用了相同的工作字典,但典型的实现应该使用一些更加量身定制的数据结构。此响应应具有a
标识符,以便主服务器将其发送到特定进程。
我认为有一些方法可以将它与你的方法一起使用,我根本不喜欢它(这本来是我的第一种方法)。但是必须处理文件描述符以及reduce_
和rebuild_
方法并不好。完全没有。
答案 1 :(得分:1)
所以,正如@MariusSiuram在this post中所解释的那样,尝试传递Connection
对象是一种令人沮丧的练习。
我最后使用DictProxy
将值从B
返回到A
。
这是概念:
### This is in the main process
...
jobs_queue = multiprocessing.Queue()
manager = multiprocessing.Manager()
ret_dict = manager.dict()
...
# Somewhere during Process initialization, jobs_queue and ret_dict got passed to
# the workers' constructor
...
### This is in the "A" (left-side) workers
...
self.ret_dict.pop(self.pid, None) # Remove our identifier if exist
self.jobs_queue.put({
'request': parameters_to_be_used_by_B,
'requester': self.pid
})
while self.pid not in self.ret_dict:
time.sleep(0.1) # Or any sane value
result = self.ret_dict[self.pid]
...
### This is in the "B" (right-side) workers
...
while True:
job = self.jobs_queue.get()
if job is None:
break
result = self.do_something(job['request'])
self.ret_dict[job['requester']] = result
...