python-45-管道与进程池的使用

前言

管道:可以互相通信、数据共享,但容易出现数据抢占问题,可以加锁解决。

进程池:每开启进程,开启属于这个进程的内存空间;能提升计算机的效率,进程过多 操作系统的调度;

一、初识管道

1、初识管道,可以互相通信。

# 1、初识管道,可以互相通信。
from multiprocessing import Pipe
conn1, conn2 = Pipe()
conn1.send('123')
print(conn2.recv())
conn2.send('321')
print(conn1.recv())

2、管道实现:生产者/消费者模型。

但是这里可能会有个问题,消费者可能同时拿同一个数据,那怎样才好呢?(接收的时候上锁:lock)

所以管道 + 锁来控制操作管道的行为 来避免进程之间争抢数据造成的数据不安全现象。

# 2、管道实现:生产者/消费者模型
from multiprocessing import Pipe,Process
import time,random
def consumer(con,pro,name):
    pro.close()
    while 1:
        try:
            m=con.recv()
            print('%s使用了 %s' % (name,m))
            time.sleep(random.random())
        except EOFError:
            con.close()
            break
def producer(con,pro,name,mask):
    con.close()
    for i in range(1,6):
        time.sleep(random.random())
        m='%s生产了%s %s'%(name,mask,i)
        print(m)
        pro.send(m)
    pro.close()
if __name__ == '__main__':
    con,pro=Pipe()
    p=Process(target=producer,args=(con,pro,'大厂','N95 '))
    p.start()
    c=Process(target=consumer,args=(con,pro,'A企业'))
    c.start()
    c1=Process(target=consumer,args=(con,pro,'B企业'))
    c1.start()
    con.close()
    pro.close()

 3、Manager,数据共享,但不安全的,进程之间也会抢占资源。

但可以加锁进行约束解决。

# 3、Manager,数据共享不安全的,但会进程之间抢占资源。
# 但可以加锁约束解决
from multiprocessing import Manager,Process,Lock
def func(dic,lock):
    # lock.acquire()
    dic['count']+=1
    # lock.release()

if __name__ == '__main__':
    lock=Lock()
    m=Manager()
    dic=m.dict({'count':0})
    p_lst=[]
    for i in range(50):
        p=Process(target=func,args=(dic,lock))
        p.start()
        p_lst.append(p)
    for i in p_lst:i.join()
    print('主进程:%s'%dic)

 加锁后:数值一直是准确的。

二、进程池

  • python中的进程池,是先创建一个属于进程的池子;
  • 进程池能指定能存放n个进程执行;

1、进程池与多进程效率对比:

同样是执行100个进程,进程池每次处理5个,而多进程for循环处理。结果进程池效率胜过多进程。

from multiprocessing import Pool,Process
import time
def func(i):
    print(i)

if __name__ == '__main__':
    # 进程池的效果
    st=time.time()
    pool=Pool(5)                # 池子可放5个(一般CPU的个数+1)
    pool.map(func,range(100))   # 100个进程任务
    t1=time.time()-st
    st=time.time()
    print('进程池时间:',t1)

    # 原来多进程的效果
    p_lst=[]
    for i in range(100):
        p=Process(target=func,args=(i,))
        p_lst.append(p)
        p.start()
    for p in p_lst:p.join()
    t2=time.time()-st
    print('多进程时间:',t2)

 2、进程池传多个参数:

#  2、进程池传多个参数:
from multiprocessing import Pool
import time
def func(i):
    print(i)

if __name__ == '__main__':
    st=time.time()
    pool=Pool(5)
    pool.map(func,[(10,'name','age'),100])

 3、apply:同步

# 3、apply:同步
from multiprocessing import Pool
import time
def func():
    print('--开始~')
    time.sleep(0.1)
    print('==结束!'+'\n')
if __name__ == '__main__':
    pool=Pool()
    for i in range(5):
        pool.apply(func)       # 同步了

 4、apply_async:异步

配合close()、join()进行使用。有没有发现进程池中的pid有重复的?那是因为进程池有固定的N个进程,所以不会变。

# 4、apply_async:异步
from multiprocessing import Pool
import time,os
def func(i):
    pid=os.getpid()
    print('%s--开始~:%s'%(i,pid))
    time.sleep(1)
if __name__ == '__main__':
    pool=Pool(2)
    for i in range(5):
        pool.apply_async(func,(i,))
    pool.close()        # 结束进程池接收任务
    pool.join()         # 感知进程池中的任务执行结束

 5、进程池的返回值:

  • apply:直接接收返回值
  • apply_async:需要get(),会堵塞因等待返回值,解决可先放列表get()
  • map:一次性返回所有返回值,自带的
# 5、进程池的返回值
# apply:直接接收返回值
# apply_async:需要get(),会堵塞因等待返回值,解决可先放列表get()。
from multiprocessing import Pool
import time
def func(i):
    time.sleep(0.5)
    return i+1
if __name__ == '__main__':
    p=Pool(3)
    p_lst=[]

    # for i in range(10):
        # res=p.apply(func,args=(i,))        # 直接接收返回值
        # print(res)

    #     res=p.apply_async(func,args=(i,))   # apply_async
    #     p_lst.append(res)
    # for i in p_lst:print(i.get())

    res=p.map(func,range(10))               # map一次性返回 
    print(res)

①apply同步返回值:

②apply_async返回值:

因3个线程,所以每次打印3个信息。

③map返回值:

6、进程池回调函数:

  • 先执行异步函数func,将func返回值传入func1函数中的ii参数。
  • 回调函数是在主进程中执行,而不是子进程中。
# 6、进程池回调函数
# 先执行异步函数func,将func返回值传入func1函数中的ii参数。
# 回调函数是在主进程中执行,而不是子进程中。
from multiprocessing import Pool
def func(i):
    return i
def func1(ii):
    print('i+1=',ii+1)
if __name__ == '__main__':
    p=Pool()
    for i in range(5):
        p.apply_async(func,args=(i,),callback=func1)
    p.close()
    p.join()

小结:

  • 管道实现的代码一般加上锁Lock
  • p=Pool():实例化;
  • p.map(函数名,可迭代类型):默认异步的执行任务,且自带close和join;
  • p.apply:同步调用;
  • p.apply_async:异步调用和主进程完全异步,需要手动close和join;

欢迎来大家QQ交流群一起学习:482713805

猜你喜欢

转载自www.cnblogs.com/gsxl/p/12588685.html