Python multi-process simple review (apply method and apply_async)

Pool进程池
multiprocessing中有两个Pool类
1. multiprocessing.Pool (进程池)
2. multiprocessinf.dummy.Pool(伪进程池<线程池>)

python 在多进程执行中存在一个python解释器的历史遗留问题
即GIL锁导致python解释器运行多进程任务时 
有且只有一个进程在执行而非多个进程同步执行

multiprocessing.Pool是假的多进程
而multiprocessing.dummy.Pool是伪多进程的多线程,
所以一般使用多进程Pool使用multiprocessing.dummy.Pool模块的
apply 阻塞 
apply()方法 只有当当前进程执行完成,才能执行下面进程

from multiprocessing import Pool
import time
import os

def talk(msg):
    print('msg',msg)
    time.sleep(3)
    print('end')

if __name__ == '__main__':
    print('开始执行程序:')
    start_time = time.time()
    pool = Pool(3)
    print('开始执行三个子进程')
    for i in range(3):
        pool.apply(talk,[i])
    print('id号:%s主进程结束 总耗时:%s' % (os.getpid(),time.time()-start_time))
输出结果
开始执行程序:
开始执行三个子进程
msg 0
end
msg 1
end
msg 2
end
id号:13228主进程结束 总耗时:9.147842645645142

2#If synchronized, only one client can access at the same time

from multiprocessing import Pool
import os,time

def work(n):
    print('%s run' % os.getpid())#输出正在运行程序进程号
    time.sleep(3)
    return n**2

if __name__ == '__main__':
    p = Pool(3)#进程池中从无到有创建3个进程,以后一直是这3个进程在执行任务
    res_l = []
    for i in range(5):
        res = p.apply(work,args=(i,))#同步调用,等到本次任务执行完毕拿到res,等待任务work执行的过程中可能有阻塞也可能没有阻塞
        #但不管该任务是否存在阻塞,同步调用都会在原地等待,只是在等的过程中若是任务发生阻塞,就会被夺走cpu的执行权限
        res_l.append(res)
    print(res_l)

输出结果
6800 run
10792 run
2532 run
6800 run
10792 run
[0, 1, 4, 9, 16]
1 p.apply(func [, args [, kwargs]])
在一个池工作进程中执行func(*args,**kwargs),然后返回结果。
需要强调的是:此操作并不会在所有池工作进程中并执行func函数。如果要通过不同参数并发地执行func函数,必须从不同线程调用p.apply()函数或者使用p.apply_async()
2 p.apply_async(func [, args [, kwargs]]):
在一个池工作进程中执行func(*args,**kwargs),然后返回结果。
此方法的结果是AsyncResult类的实例,callback是可调用对象,接收输入参数。当func的结果变为可用时,
将理解传递给callback。callback禁止执行任何阻塞操作,否则将接收其他异步操作中的结果。   
3 p.close():关闭进程池,防止进一步操作。如果所有操作持续挂起,它们将在工作进程终止前完成
4 P.jion():等待所有工作进程退出。此方法只能在close()或teminate()之后调用
apply_async()非阻塞
apply_async()方法 当前进程没有执行完成,下面的进程也可以执行
from multiprocessing import Pool
import time,os

def talk(msg):
    print('msg:',msg)
    time.sleep(3)
    print('end')
    
if __name__ == '__main__':
    print("开始执行程序")
    start_time = time.time()
    pool = Pool(3)
    print("开始执行三个子进程")
    for i in range(3):
        pool.apply_async(talk,[i])
    print('id号:%s主进程结束 总耗时:%s' %(os.getpid(),time.time()-start_time))
开始执行程序
开始执行三个子进程
id号:18836主进程结束 总耗时:0.03989410400390625
from multiprocessing import Pool
import os,time

def work(n):
    print('%s run' %os.getpid())
    time.sleep(3)
    return n**2
if __name__ == '__main__':
    p = Pool(3)#进程池中从无到有创建三个子进程,以后一直是这三个进程在执行任务
    res_l = []
    for i in range(5):
        res = p.apply_async(work,args=(i,))#运行 阻塞 直到本次任务执行完毕拿到res
        res_l.append(res)
    #异步apply_async用法 :如果使用异步提交的任务,主进程需要使用join,等待进程池内任务都处理完,
    #可以用get 收集结果,否则,主进程结束,进程池可能还没来得及执行,也跟着一起结束了
    p.close()
    p.join()
    for res in res_l:
        print(res.get())#使用get来获取apply_async的结果,
        #如果是apply,则没有get方法,因为apply是同步执行,立即获取结果,根本不需要get
执行结果
14516 run
11948 run
7520 run
14516 run
11948 run
0
1
4
9
16

Process pool (asynchronous call, apply_async\\\synchronous call, apply)

一,使用进程池(异步调用,apply_async)
from multiprocessing import Process,Pool
import time

def func(msg):
    print("msg : ",msg)
    time.sleep(1)
    return msg

if __name__ == '__main__':
    pool = Pool(processes=3)
    res_l = []
    for i in range(5):
        msg = 'hello %d' %(i)
        res = pool.apply_async(func,(msg,))#维持执行进程总数为3, 当一个进程执行完毕,会添加新的进程进去
        res_l.append(res)
    print("=================>")#没有后面的join/get,则程序整体结束,进程池中的任务还没来的及全部执行,也跟着主进程一起结束

    pool.close()#关闭进程池,防止进一步操作。
    pool.join()#调用join之前,先调用close函数,否则会出错,执行完close之后不会有新的进程加入到pool,join函数等待所有子进程结束

    print(res_l)#输出的是<multiprocessing.pool.ApplyResult object at 0x000001C9E5E9E128>对象组成列表,
    #而非最终结果,但这一步在join之后进行,证明结果已经计算完毕,
    #剩下的事情就是调用每个对象下的get方法去获取结果
    for i in res_l:
        print(i.get()) #使用get来获取apply_async的结果
        #如果是apply 则没有get方法,因为apply是同步执行,立即获取结果,根本无需get
二 使用进程池,同步调用 apply
from multiprocessing import Process,Pool
import time

def func(msg):
    print('msg :',msg)
    time.sleep(0.1)
    return msg

if __name__ == '__main__':
    pool = Pool(processes = 3)
    res_l = []
    for i in range(5):
        msg = "hello %d" %i
        res = pool.apply(func,(msg,)) #维持执行的进程总数为processes,当一个进程执行完毕后会添加新的进程进去
        res_l.append(res)#同步执行,即执行完一个拿到结果,再去执行另外一个
    print("===================>")
    pool.close()
    pool.join() #调用join之前,先调用close函数,否则会出错。执行完close后不会有新的进程加入到pool,join函数等待所有子进程结束

    print(res_l)#看到的就是最终的结果组成的列表
    for i in res_l: #apply是同步的,所以直接得到结果,没有get()方法
        print(i)
msg : hello 0
msg : hello 1
msg : hello 2
msg : hello 3
msg : hello 4
===================>
['hello 0', 'hello 1', 'hello 2', 'hello 3', 'hello 4']
hello 0
hello 1
hello 2
hello 3
hello 4
callback 函数初识--回调函数
callback 参数是一个函数名,其参数来源是第一个函数传来参数,
代码中b()函数有返回值,就传给了callback函数参数
注意 callback 参数可选
from multiprocessing import Process,Pool

def a(x):
    print("程序开始")
    print(x)
    print("程序结束")
    
def b(num):
    return num

if __name__ == '__main__':
    p = Pool(3)
    for i in range(5):
        p.apply_async(b,args=(i,),callback=a)#当b函数执行完就调用a函数,并将b函数的返回值传给a函数
    p.close()
    p.join()
程序开始
0
程序结束
程序开始
1
程序结束
程序开始
2
程序结束
程序开始
3
程序结束
程序开始
4
程序结束

Guess you like

Origin blog.csdn.net/weixin_42540340/article/details/108327300