python执行多进程时,如何获取函数返回的值

python执行多进程时,如何获取函数返回的值,第1张

共享变量的方法。

没有办法直接实现你的需求,但是,你可以用共享变量的方法实现,比如:

def worker(procnum, return_dict):

'''worker function'''

print str(procnum) + ' represent!'

return_dict[procnum] = procnumif __name__ == '__main__':

manager = Manager()

return_dict = managerdict()

jobs = []    for i in range(5):

p = multiprocessingProcess(target=worker, args=(i,return_dict))

jobsappend(p)

pstart()    for proc in jobs:

procjoin()    print return_dictvalues()

想要充分利用多核CPU资源,Python中大部分情况下都需要使用多进程,Python中提供了multiprocessing这个包实现多进程。multiprocessing支持子进程、进程间的同步与通信,提供了Process、Queue、Pipe、Lock等组件。

开辟子进程

multiprocessing中提供了Process类来生成进程实例

Process([group [, target [, name [, args [, kwargs]]]]])

group分组,实际上不使用

target表示调用对象,你可以传入方法的名字

args表示给调用对象以元组的形式提供参数,比如target是函数a,他有两个参数m,n,那么该参数为args=(m, n)即可

kwargs表示调用对象的字典

name是别名,相当于给这个进程取一个名字

先来个小例子:

# -- coding:utf-8 --

from multiprocessing import Process, Pool

import os

import time

def run_proc(wTime):

n = 0

while n < 3:

print "subProcess %s run," % osgetpid(), "{0}"format(timectime()) #获取当前进程号和正在运行是的时间

timesleep(wTime) #等待(休眠)

n += 1

if __name__ == "__main__":

p = Process(target=run_proc, args=(2,)) #申请子进程

pstart() #运行进程

print "Parent process run subProcess is ", ppid

print "Parent process end,{0}"format(timectime())

运行结果:

Parent process run subProcess is 30196

Parent process end,Mon Mar 27 11:20:21 2017

subProcess 30196 run, Mon Mar 27 11:20:21 2017

subProcess 30196 run, Mon Mar 27 11:20:23 2017

subProcess 30196 run, Mon Mar 27 11:20:25 2017

根据运行结果可知,父进程运行结束后子进程仍然还在运行,这可能造成僵尸( zombie)进程。

通常情况下,当子进程终结时,它会通知父进程,清空自己所占据的内存,并在内核里留下自己的退出信息。父进程在得知子进程终结时,会从内核中取出子进程的退出信息。但是,如果父进程早于子进程终结,这可能造成子进程的退出信息滞留在内核中,子进程成为僵尸(zombie)进程。当大量僵尸进程积累时,内存空间会被挤占。

有什么办法可以避免僵尸进程呢?

这里介绍进程的一个属性 deamon,当其值为TRUE时,其父进程结束,该进程也直接终止运行(即使还没运行完)。

所以给上面的程序加上pdeamon = true,看看效果。

# -- coding:utf-8 --

from multiprocessing import Process, Pool

import os

import time

def run_proc(wTime):

n = 0

while n < 3:

print "subProcess %s run," % osgetpid(), "{0}"format(timectime())

timesleep(wTime)

n += 1

if __name__ == "__main__":

p = Process(target=run_proc, args=(2,))

pdaemon = True #加入daemon

pstart()

print "Parent process run subProcess is ", ppid

print "Parent process end,{0}"format(timectime())

执行结果:

Parent process run subProcess is 31856

Parent process end,Mon Mar 27 11:40:10 2017

这是问题又来了,子进程并没有执行完,这不是所期望的结果。有没办法将子进程执行完后才让父进程结束呢?

这里引入pjoin()方法,它使子进程执行结束后,父进程才执行之后的代码

# -- coding:utf-8 --

from multiprocessing import Process, Pool

import os

import time

def run_proc(wTime):

n = 0

while n < 3:

print "subProcess %s run," % osgetpid(), "{0}"format(timectime())

timesleep(wTime)

n += 1

if __name__ == "__main__":

p = Process(target=run_proc, args=(2,))

pdaemon = True

pstart()

pjoin() #加入join方法

print "Parent process run subProcess is ", ppid

print "Parent process end,{0}"format(timectime())

执行结果:

subProcess 32076 run, Mon Mar 27 11:46:07 2017

subProcess 32076 run, Mon Mar 27 11:46:09 2017

subProcess 32076 run, Mon Mar 27 11:46:11 2017

Parent process run subProcess is 32076

Parent process end,Mon Mar 27 11:46:13 2017

这样所有的进程就能顺利的执行了。

上篇文章简单介绍了multiprocessing模块,本文将要介绍进程之间的数据共享和信息传递的概念。

在多进程处理中,所有新创建的进程都会有这两个特点:独立运行,有自己的内存空间。

我们来举个例子展示一下:

这个程序的输出结果是:

在上面的程序中我们尝试在两个地方打印全局列表result的内容:

我们再用一张图来帮助理解记忆不同进程间的数据关系:

如果程序需要在不同的进程之间共享一些数据的话,该怎么做呢?不用担心,multiprocessing模块提供了Array对象和Value对象,用来在进程之间共享数据。

所谓Array对象和Value对象分别是指从共享内存中分配的ctypes数组和对象。我们直接来看一个例子,展示如何用Array对象和Value对象在进程之间共享数据:

程序输出的结果如下:

成功了!主程序和p1进程输出了同样的结果,说明程序中确实完成了不同进程间的数据共享。那么我们来详细看一下上面的程序做了什么:

在主程序中我们首先创建了一个Array对象:

向这个对象输入的第一个参数是数据类型:i表示整数,d代表浮点数。第二个参数是数组的大小,在这个例子中我们创建了包含4个元素的数组。

类似的,我们创建了一个Value对象:

我们只对Value对象输入了一个参数,那就是数据类型,与上述的方法一致。当然,我们还可以对其指定一个初始值(比如10),就像这样:

随后,我们在创建进程对象时,将刚创建好的两个对象:result和square_sum作为参数输入给进程:

在函数中result元素通过索引进行数组赋值,square_sum通过 value 属性进行赋值。

注意:为了完整打印result数组的结果,需要使用 result[:] 进行打印,而square_sum也需要使用 value 属性进行打印:

每当python程序启动时,同时也会启动一个服务器进程。随后,只要我们需要生成一个新进程,父进程就会连接到服务器并请求它派生一个新进程。这个服务器进程可以保存Python对象,并允许其他进程使用代理来 *** 作它们。

multiprocessing模块提供了能够控制服务器进程的Manager类。所以,Manager类也提供了一种创建可以在不同流程之间共享的数据的方法。

服务器进程管理器比使用共享内存对象更灵活,因为它们可以支持任意对象类型,如列表、字典、队列、值、数组等。此外,单个管理器可以由网络上不同计算机上的进程共享。

但是,服务器进程管理器的速度比使用共享内存要慢。

让我们来看一个例子:

这个程序的输出结果是:

我们来理解一下这个程序做了什么:首先我们创建了一个manager对象

在with语句下的所有行,都是在manager对象的范围内的。接下来我们使用这个manager对象创建了列表(类似的,我们还可以用 managerdict() 创建字典)。

最后我们创建了进程p1(用于在records列表中插入一条新的record)和p2(将records打印出来),并将records作为参数进行传递。

服务器进程的概念再次用下图总结一下:

为了能使多个流程能够正常工作,常常需要在它们之间进行一些通信,以便能够划分工作并汇总最后的结果。multiprocessing模块支持进程之间的两种通信通道:Queue和Pipe。

使用队列来回处理多进程之间的通信是一种比较简单的方法。任何Python对象都可以使用队列进行传递。我们来看一个例子:

上面这个程序的输出结果是:

我们来看一下上面这个程序到底做了什么。首先我们创建了一个Queue对象:

然后,将这个空的Queue对象输入square_list函数。该函数会将列表中的数平方,再使用 put() 方法放入队列中:

随后使用 get() 方法,将q打印出来,直至q重新称为一个空的Queue对象:

我们还是用一张图来帮助理解记忆:

一个Pipe对象只能有两个端点。因此,当进程只需要双向通信时,它会比Queue对象更好用。

multiprocessing模块提供了 Pipe() 函数,该函数返回由管道连接的一对连接对象。 Pipe() 返回的两个连接对象分别表示管道的两端。每个连接对象都有 send() 和 recv() 方法。

我们来看一个例子:

上面这个程序的输出结果是:

我们还是来看一下这个程序到底做了什么。首先创建了一个Pipe对象:

与上文说的一样,该对象返回了一对管道两端的两个连接对象。然后使用 send() 方法和 recv() 方法进行信息的传递。就这么简单。在上面的程序中,我们从一端向另一端发送一串消息。在另一端,我们收到消息,并在收到END消息时退出。

要注意的是,如果两个进程(或线程)同时尝试从管道的同一端读取或写入管道中的数据,则管道中的数据可能会损坏。不过不同的进程同时使用管道的两端是没有问题的。还要注意,Queue对象在进程之间进行了适当的同步,但代价是增加了计算复杂度。因此,Queue对象对于线程和进程是相对安全的。

最后我们还是用一张图来示意:

Python的multiprocessing模块还剩最后一篇文章:多进程的同步与池化

敬请期待啦!

以上就是关于python执行多进程时,如何获取函数返回的值全部的内容,包括:python执行多进程时,如何获取函数返回的值、python可以多进程吗、Python多进程运行——Multiprocessing基础教程2等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/10039944.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-04
下一篇 2023-05-04

发表评论

登录后才能评论

评论列表(0条)

保存