Python获取多进程执行的返回值

Posted 执假以为真

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python获取多进程执行的返回值相关的知识,希望对你有一定的参考价值。

Python获取多进程执行的返回值

众所周知,因为GIL的原因,Python至今不支持真正的多线程。为了达到并行运行的目的,我们往往就需要运行多进程了。
一个任务由一个进程来运行,可是它的结果怎么来获取呢?

方法-1.

第一种方法是记录在全局变量中。当然这时候要注意可能会需要用到Lock. 下面是一个例子。

Program-1

import multiprocessing
from multiprocessing import Pool


info_manager = multiprocessing.Manager()
info_lock = info_manager.Lock()
info_dict = info_manager.dict()


def add(n):
    global info_dict, info_lock 
    
    s = 0
    for i in range(n+1):
        s += i
    
    info_lock.acquire()
    info_dict[n] = s
    info_lock.release()
    
    print("In task %d: %d -> %d" % (n, n, s))


def calculate():
    pool = Pool(processes=4) 

    tasks = range(10)
    for n in tasks:
        pool.apply_async(add, (n,))
        
    pool.close()
    pool.join()
    
    
def print_result():
    global info_dict
    
    key_list = sorted(info_dict.keys())
    
    for key in key_list:
        print("%s: %s" % (key, info_dict[key])) 
    
    
if __name__ == '__main__':
    calculate()
    print_result()
    

除了使用全局变量,还有没有其他的方法呢?毕竟全局变量似乎看起来有点危险,不小心就会被弄坏。

方法-2.

第二种方法,就是记录下multiprocessing.Pool.apply_async的返回值(假设称之为result),然后在Pool被join之后,利用result.get()方法来得到原任务函数的返回值。在这里,multiprocessing.Pool.apply_async的返回值的类型是multiprocessing.pool.ApplyResult,其get()方法会返回原任务函数的返回值。

下面是把上面的那个例子重新写一遍。
Program-2

import multiprocessing
from multiprocessing import Pool


def add(n):
    s = 0
    for i in range(n+1):
        s += i
    return (n, s)


def calculate():
    pool = Pool(processes=4)

    tasks = range(10)
    result_list = list()
    info_dict = dict()
    
    for n in tasks:
        result_list.append(pool.apply_async(add, (n,)))
        
    pool.close()
    pool.join()
    
    for result in result_list:
        k, v = result.get()
        info_dict[k] = v
        
    return info_dict
    
    
def print_result():
    info_dict = calculate()
    
    key_list = sorted(info_dict.keys())
    
    for key in key_list:
        print("%s: %s" % (key, info_dict[key])) 
    
    
if __name__ == '__main__':
    calculate()
    print_result()
    

另外,其实也可以不用等到 Pool join 之后才能调get(). 可以立刻调用get(), 但这可能会造成阻塞。
get()函数其实有一个参数,可以指定超时时间以免无限等下去,如,result.get(timeout=2), 就是设置超时为2秒。

其定义在Python3中如下:

get([timeout])
    Return the result when it arrives. 
    If timeout is not None and the result does not arrive within timeout seconds 
    then multiprocessing.TimeoutError is raised. 
    If the remote call raised an exception then that exception will be reraised by get().

也就是说,如果超时了,就会抛出一个multiprocessing.TimeoutError异常;
而如果该任务进程内抛了异常,也会被get()重新抛出来。

本文程序通过Python2和Python3的测试。

(END)

pythonNet 04多进程

fork注意:
*进入阻塞态的进程一定会让出cpu时间片
*各个进程在自己空间内对数据的操作不影响其他进程
*父进程在执行fork之前开辟的空间子进程也会复制

进程相关函数

os.getpid()
功能获取当前进程的PID号
返回值:返回当前进程的PID

os.getppid()
功能;获取父进程的PID号
返回值:返回父进程PID

os._exit(status)
功能:退出程序
参数:整数 表示自定义的进程退出状态标识

sys.exit([status])
功能:退出进程
参数:整数 表示退出状态 默认为0
        传一个字符串,则退出时会打印该字符串


孤儿进程和僵尸进程

孤儿进程;父进程先于子进程退出,则子进程成为孤儿进程

*孤儿进程会被系统进程收养,此时系统进程就好成为该进程父进程

僵尸进程:子进程先于父进程退出,父进程没有处理子进程退出状态,此时子进程就会成为僵尸进程

*僵尸进程虽然结束但是会存留部分PCB在内存,大量的僵尸进程会占用内存资源


如何避免僵尸进程产生
    *处理自己成退出状态
    pid,status =os.wait()
    功能;在父进程中阻塞等待子进程退出
    返回值:pid 退出的子进程的PID
            status 子进程退出状态


    pid,status =os.waitpid(pid,option)
    功能;在父进程中等待子进程退出
    参数:pid -1 表示等待任意子进程
             >0 表示等待指定PID的子进程退出
          option 0表示阻塞等待
                WNOHANG 表示非阻塞
    返回值:pid 退出的子进程的PID
            status 子进程的退出状态

    创建二级子进程
    1.父进程创建子进程等待子进程退出
    2.子进程创建二级子进程然后退出
    3.二级子进程成为孤儿,和原来父进程各自执行任务

 

 

 































以上是关于Python获取多进程执行的返回值的主要内容,如果未能解决你的问题,请参考以下文章

python多进程,并获取每个进程的返回值

python 获取subprocess进程执行后返回值

pythonNet 04多进程

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

如何使用线程去执行一个 有返回值的方法,并获取返回值?

python线程间通信的问题,回答有加分!300