Python 如何恢复传递给multiprocessing.Process的函数的返回值?

Python 如何恢复传递给multiprocessing.Process的函数的返回值?,python,python-multiprocessing,Python,Python Multiprocessing,在下面的示例代码中,我想恢复函数worker的返回值。我该怎么做呢?这个值存储在哪里 示例代码: import multiprocessing def worker(procnum): '''worker function''' print str(procnum) + ' represent!' return procnum if __name__ == '__main__': jobs = [] for i in range(5):

在下面的示例代码中,我想恢复函数
worker
的返回值。我该怎么做呢?这个值存储在哪里

示例代码:

import multiprocessing

def worker(procnum):
    '''worker function'''
    print str(procnum) + ' represent!'
    return procnum


if __name__ == '__main__':
    jobs = []
    for i in range(5):
        p = multiprocessing.Process(target=worker, args=(i,))
        jobs.append(p)
        p.start()

    for proc in jobs:
        proc.join()
    print jobs
0 represent!
1 represent!
2 represent!
3 represent!
4 represent!
[<Process(Process-1, stopped)>, <Process(Process-2, stopped)>, <Process(Process-3, stopped)>, <Process(Process-4, stopped)>, <Process(Process-5, stopped)>]
0 represent!
1 represent!
2 represent!
3 represent!
4 represent!
[0, 1, 2, 3, 4]
0 represent!
1 represent!
2 represent!
3 represent!
4 represent!
['0 represent!', '1 represent!', '2 represent!', '3 represent!', '4 represent!']
输出:

import multiprocessing

def worker(procnum):
    '''worker function'''
    print str(procnum) + ' represent!'
    return procnum


if __name__ == '__main__':
    jobs = []
    for i in range(5):
        p = multiprocessing.Process(target=worker, args=(i,))
        jobs.append(p)
        p.start()

    for proc in jobs:
        proc.join()
    print jobs
0 represent!
1 represent!
2 represent!
3 represent!
4 represent!
[<Process(Process-1, stopped)>, <Process(Process-2, stopped)>, <Process(Process-3, stopped)>, <Process(Process-4, stopped)>, <Process(Process-5, stopped)>]
0 represent!
1 represent!
2 represent!
3 represent!
4 represent!
[0, 1, 2, 3, 4]
0 represent!
1 represent!
2 represent!
3 represent!
4 represent!
['0 represent!', '1 represent!', '2 represent!', '3 represent!', '4 represent!']
0代表!
我代表!
2代表!
3代表!
4代表!
[, , ]
作业
中存储的用于通信的对象中,我似乎找不到相关属性。例如:

 AttributeError: Can't get attribute 'worker' on <module '__main__' (built-in)>
导入多处理
def工作程序(procnum,返回指令):
“工作函数”
打印(str(procnum)+“表示!”)
return_dict[procnum]=procnum
如果名称=“\uuuuu main\uuuuuuuu”:
manager=multiprocessing.manager()
return\u dict=manager.dict()
工作=[]
对于范围(5)中的i:
p=多处理。进程(目标=工作者,参数=(i,返回命令))
jobs.append(p)
p、 开始()
对于作业中的proc:
proc.join()
打印(返回默认值())

看来您应该改用类,使用方法。apply()。apply\u async(),map()


我认为@sega_sai建议的方法更好。但它确实需要一个代码示例,因此:

import multiprocessing
from os import getpid

def worker(procnum):
    print('I am number %d in process %d' % (procnum, getpid()))
    return getpid()

if __name__ == '__main__':
    pool = multiprocessing.Pool(processes = 3)
    print(pool.map(worker, range(5)))
它将打印返回值:

I am number 0 in process 19139
I am number 1 in process 19138
I am number 2 in process 19140
I am number 3 in process 19139
I am number 4 in process 19140
[19139, 19138, 19140, 19139, 19140]
如果您熟悉
map
(Python2内置),这应该不会太有挑战性。否则就看一看


请注意,所需的代码是多么少。(还要注意流程的重复使用方式)。

您可以使用内置的
退出
设置流程的退出代码。它可以从流程的
exitcode
属性中获得:

import multiprocessing

def worker(procnum):
    print str(procnum) + ' represent!'
    exit(procnum)

if __name__ == '__main__':
    jobs = []
    for i in range(5):
        p = multiprocessing.Process(target=worker, args=(i,))
        jobs.append(p)
        p.start()

    result = []
    for proc in jobs:
        proc.join()
        result.append(proc.exitcode)
    print result
输出:

import multiprocessing

def worker(procnum):
    '''worker function'''
    print str(procnum) + ' represent!'
    return procnum


if __name__ == '__main__':
    jobs = []
    for i in range(5):
        p = multiprocessing.Process(target=worker, args=(i,))
        jobs.append(p)
        p.start()

    for proc in jobs:
        proc.join()
    print jobs
0 represent!
1 represent!
2 represent!
3 represent!
4 represent!
[<Process(Process-1, stopped)>, <Process(Process-2, stopped)>, <Process(Process-3, stopped)>, <Process(Process-4, stopped)>, <Process(Process-5, stopped)>]
0 represent!
1 represent!
2 represent!
3 represent!
4 represent!
[0, 1, 2, 3, 4]
0 represent!
1 represent!
2 represent!
3 represent!
4 represent!
['0 represent!', '1 represent!', '2 represent!', '3 represent!', '4 represent!']

对于正在寻求如何使用
队列从
进程
获取值的任何其他人:

import multiprocessing

ret = {'foo': False}

def worker(queue):
    ret = queue.get()
    ret['foo'] = True
    queue.put(ret)

if __name__ == '__main__':
    queue = multiprocessing.Queue()
    queue.put(ret)
    p = multiprocessing.Process(target=worker, args=(queue,))
    p.start()
    p.join()
    print(queue.get())  # Prints {"foo": True}
请注意,在Windows或Jupyter笔记本电脑中,使用
多线程
时,必须将其保存为文件并执行该文件。如果在命令提示符下执行此操作,您将看到如下错误:

 AttributeError: Can't get attribute 'worker' on <module '__main__' (built-in)>
AttributeError:无法在上获取属性“worker”

此示例演示如何使用实例列表从任意数量的进程返回字符串:

import multiprocessing

def worker(procnum, send_end):
    '''worker function'''
    result = str(procnum) + ' represent!'
    print result
    send_end.send(result)

def main():
    jobs = []
    pipe_list = []
    for i in range(5):
        recv_end, send_end = multiprocessing.Pipe(False)
        p = multiprocessing.Process(target=worker, args=(i, send_end))
        jobs.append(p)
        pipe_list.append(recv_end)
        p.start()

    for proc in jobs:
        proc.join()
    result_list = [x.recv() for x in pipe_list]
    print result_list

if __name__ == '__main__':
    main()
输出:

import multiprocessing

def worker(procnum):
    '''worker function'''
    print str(procnum) + ' represent!'
    return procnum


if __name__ == '__main__':
    jobs = []
    for i in range(5):
        p = multiprocessing.Process(target=worker, args=(i,))
        jobs.append(p)
        p.start()

    for proc in jobs:
        proc.join()
    print jobs
0 represent!
1 represent!
2 represent!
3 represent!
4 represent!
[<Process(Process-1, stopped)>, <Process(Process-2, stopped)>, <Process(Process-3, stopped)>, <Process(Process-4, stopped)>, <Process(Process-5, stopped)>]
0 represent!
1 represent!
2 represent!
3 represent!
4 represent!
[0, 1, 2, 3, 4]
0 represent!
1 represent!
2 represent!
3 represent!
4 represent!
['0 represent!', '1 represent!', '2 represent!', '3 represent!', '4 represent!']
此解决方案使用的资源比使用

  • 烟斗
  • 至少有一把锁
  • 缓冲区
  • 线
或者使用

  • 烟斗
  • 至少有一把锁

查看每种类型的源代码非常有启发性。

我稍微修改了vartec的答案,因为我需要从函数中获取错误代码。(谢谢vertec!!!这是一个很棒的把戏)

这也可以通过一个
管理器来完成。list
但是我认为最好将它放在dict中并在其中存储一个列表。这样,我们就保留了函数和结果,因为我们无法确定列表的填充顺序

from multiprocessing import Process
import time
import datetime
import multiprocessing


def func1(fn, m_list):
    print 'func1: starting'
    time.sleep(1)
    m_list[fn] = "this is the first function"
    print 'func1: finishing'
    # return "func1"  # no need for return since Multiprocess doesnt return it =(

def func2(fn, m_list):
    print 'func2: starting'
    time.sleep(3)
    m_list[fn] = "this is function 2"
    print 'func2: finishing'
    # return "func2"

def func3(fn, m_list):
    print 'func3: starting'
    time.sleep(9)
    # if fail wont join the rest because it never populate the dict
    # or do a try/except to get something in return.
    raise ValueError("failed here")
    # if we want to get the error in the manager dict we can catch the error
    try:
        raise ValueError("failed here")
        m_list[fn] = "this is third"
    except:
        m_list[fn] = "this is third and it fail horrible"
        # print 'func3: finishing'
        # return "func3"


def runInParallel(*fns):  # * is to accept any input in list
    start_time = datetime.datetime.now()
    proc = []
    manager = multiprocessing.Manager()
    m_list = manager.dict()
    for fn in fns:
        # print fn
        # print dir(fn)
        p = Process(target=fn, name=fn.func_name, args=(fn, m_list))
        p.start()
        proc.append(p)
    for p in proc:
        p.join()  # 5 is the time out

    print datetime.datetime.now() - start_time
    return m_list, proc

if __name__ == '__main__':
    manager, proc = runInParallel(func1, func2, func3)
    # print dir(proc[0])
    # print proc[0]._name
    # print proc[0].name
    # print proc[0].exitcode

    # here you can check what did fail
    for i in proc:
        print i.name, i.exitcode  # name was set up in the Process line 53

    # here will only show the function that worked and where able to populate the 
    # manager dict
    for i, j in manager.items():
        print dir(i)  # things you can do to the function
        print i, j

出于某种原因,我在任何地方都找不到一个关于如何使用
Queue
执行此操作的通用示例(即使是Python的文档示例也不会产生多个进程),因此我在尝试了10次之后得到了以下结果:

def add_helper(queue, arg1, arg2): # the func called in child processes
    ret = arg1 + arg2
    queue.put(ret)

def multi_add(): # spawns child processes
    q = Queue()
    processes = []
    rets = []
    for _ in range(0, 100):
        p = Process(target=add_helper, args=(q, 1, 2))
        processes.append(p)
        p.start()
    for p in processes:
        ret = q.get() # will block
        rets.append(ret)
    for p in processes:
        p.join()
    return rets
队列
是一个阻塞的线程安全队列,可用于存储子进程的返回值。因此,您必须将队列传递给每个进程。这里不太明显的一点是,在加入
进程之前,您必须从队列中
获取()
,否则队列将填满并阻塞所有内容

更新面向对象(在Python 3.4中测试)的用户:

一个简单的解决方案:

import multiprocessing

output=[]
data = range(0,10)

def f(x):
    return x**2

def handler():
    p = multiprocessing.Pool(64)
    r=p.map(f, data)
    return r

if __name__ == '__main__':
    output.append(handler())

print(output[0])
输出:

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
0 represent!
1 represent!
2 represent!
3 represent!
4 represent!
[0, 1, 2, 3, 4]
这个包有一个很好的抽象,它利用了
多处理.Pipe
,这使得它非常简单:

从pebble导入并发
@并发进程
def函数(arg,kwarg=0):
返回arg+kwarg
未来=功能(1,kwarg=1)
打印(future.result())

示例来源:

如果您使用的是Python 3,则可以使用以下内容作为方便的抽象:

from concurrent.futures import ProcessPoolExecutor

def worker(procnum):
    '''worker function'''
    print(str(procnum) + ' represent!')
    return procnum


if __name__ == '__main__':
    with ProcessPoolExecutor() as executor:
        print(list(executor.map(worker, range(5))))
输出:

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
0 represent!
1 represent!
2 represent!
3 represent!
4 represent!
[0, 1, 2, 3, 4]

我想我应该简化上面复制的最简单的例子,为我在Py3.6上工作。最简单的是:

您可以使用设置池中进程的数量,例如,
池(进程=5)
。但是,它默认为CPU计数,因此对于CPU限制的任务,将其留空。(I/O绑定的任务通常适合线程,因为线程大部分都在等待,因此可以共享CPU核心。)
池也适用

(请注意,worker方法不能嵌套在方法中。我最初在调用
pool.map
的方法中定义了我的worker方法,以使其保持所有自包含,但随后进程无法导入它,并抛出了“AttributeError:无法pickle本地对象外部\u方法..内部\u方法”。更多。它可以在类内。)

(请欣赏打印
'represente!'
而不是
time.sleep()
时指定的原始问题,但是如果没有它,我认为有些代码是并发运行的,而它不是。)


Py3也是两行(
.map
返回一个生成器,因此需要
列表()
):


使用普通的es:


如果您只需要
put
get
就可以使用。第一个循环启动所有进程,然后第二个循环进行阻塞
队列.get
调用。我认为没有任何理由也调用
p.join()

我建议在这里使用,而不是
管理器。使用
管理器
需要生成一个全新的进程,如果
队列
可以,这就太过了。@dano:我想知道,如果我们使用Queue()对象,我们无法确定每个进程返回值的顺序。我的意思是,如果我们需要结果中的顺序,就要做下一步的工作。我们怎样才能确切地确定哪一个输出来自哪一个process@Catbuilts您可以从每个进程返回一个元组,其中一个值是您关心的实际返回值,而