首页 > 编程语言 > 详细

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

时间:2020-03-29 00:53:55      阅读:65      评论:0      收藏:0      [点我收藏+]

前言

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

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

一、初识管道

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

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

原文:https://www.cnblogs.com/gsxl/p/12588685.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!