Python全栈学习笔记day 38:进程间通信:管道(multiprocessing.Pipe)、进程之间的数据共享(multiprocessing.Manager)、进池Pool模块、回调函数


目录

一、进程间通信:管道(multiprocess.Pipe)

二、管道实现生产者消费模型

三、进程之间的数据共享

四、进程池和multiprocessing.Pool模块

五、回调函数



一、进程间通信:管道(multiprocess.Pipe)

管道示意图:

子进程接收主进程消息:

from multiprocessing import Pipe,Process

def func(conn1,conn2):
    conn2.close()
    while True:
        try :
            msg = conn1.recv()
            print(msg)
        except EOFError:
            conn1.close()
            break

if __name__ == '__main__':
    conn1, conn2 = Pipe()
    Process(target=func,args = (conn1,conn2)).start()
    conn1.close()
    for i in range(20):
        conn2.send('吃了么')
    conn2.close()

代码解释:
EOFError:管道取完所有数后,继续取数据时所报的错误
同一个管道在主进程管道口A(conn1.close())的关闭,不会影响子进程的管道口A的接受数据(conn1.recv())

二、管道实现生产者消费模型

from multiprocessing import Process,Pipe,Lock

def consumer(produce, consume,name,lock):
    produce.close()
    while True:
        lock.acquire()
        baozi=consume.recv()
        lock.release()
        if baozi:
            print('%s 收到包子:%s' %(name,baozi))
        else:
            consume.close()
            break

def producer(produce, consume,n):
    consume.close()
    for i in range(n):
        produce.send(i)
    produce.send(None)
    produce.send(None)
    produce.close()

if __name__ == '__main__':
    produce,consume=Pipe()
    lock = Lock()
    c1=Process(target=consumer,args=(produce,consume,'c1',lock))
    c2=Process(target=consumer,args=(produce,consume,'c2',lock))
    p1=Process(target=producer,args=(produce,consume,30))
    c1.start()
    c2.start()
    p1.start()
    produce.close()
    consume.close()

三、进程之间的数据共享

进程间数据是独立的,可以借助于队列或管道实现通信,二者都是基于消息传递的
虽然进程间数据独立,但可以通过Manager实现数据共享,事实上Manager的功能远不止于此

加了锁的数据共享:

from multiprocessing import Manager,Process,Lock
def main(dic,lock):
    lock.acquire()
    dic['count'] -= 1
    lock.release()

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

先实例化:m = Manager()

共享的是:dic=m.dict({'count':100})        带上m就可以共享

四、进程池和multiprocessing.Pool模块

为什么要有进程池?进程池的概念。

在程序实际处理问题过程中,忙时会有成千上万的任务需要被执行,闲时可能只有零星任务。那么在成千上万个任务需要被执行的时候,我们就需要去创建成千上万个进程么?首先,创建进程需要消耗时间,销毁进程也需要消耗时间。第二即便开启了成千上万的进程,操作系统也不能让他们同时执行,这样反而会影响程序的效率。因此我们不能无限制的根据任务开启或者结束进程。那么我们要怎么做呢?

在这里,要给大家介绍一个进程池的概念,定义一个池子,在里面放上固定数量的进程,有需求来了,就拿一个池中的进程来处理任务,等到处理完毕,进程并不关闭,而是将进程再放回进程池中继续等待任务。如果有很多任务需要执行,池中的进程数量不够,任务就要等待之前的进程执行任务完毕归来,拿到空闲进程才能继续执行。也就是说,池中进程的数量是固定的,那么同一时间最多有固定数量的进程在运行。这样不会增加操作系统的调度难度,还节省了开闭进程的时间,也一定程度上能够实现并发效果。

 Python中进程池:
    python中的 先创建一个属于进程的池子
    这个池子指定能存放n个进程
    先讲这些进程创建好
 更高级的进程池(Python中没有):
     进程的上限:n,进程的下限:m 。 任务少时,进程池中有m 个进程。任务多很时,进程池中有n 个进程。可以自动调节
  

apply_async程序格式:

import os
import time
from multiprocessing import Pool
def func(n):
    print('start func%s'%n,os.getpid())
    time.sleep(1)
    print('end func%s' % n,os.getpid())

if __name__ == '__main__':
    p = Pool(5)            池中有5个进程
    for i in range(10):
        p.apply_async(func,args=(i,))        apply_async是异步执行任务
    p.close()               结束进程池接收任务
    p.join()                感知进程池中的任务执行结束

 p.apply_async(要执行任务的函数名,args=以元祖的形式传参数)       
    p.close() 和  p.join()   必须紧更着后面         

进程池中执行任务这步可以换成:

p.map(funcname,iterable)     默认异步的执行任务,且自带close和join
p.apply   同步调用的
p.apply_async 异步调用 和主进程完全异步 需要手动close 和 join 

栗子:(有返回值的apply)

from multiprocessing import Pool
def func(i):
    return i*i

if __name__ == '__main__':
    p = Pool(5)
    for i in range(10):
        res = p.apply(func,args=(i,))   # apply的结果就是func的返回值
        print(res)


0
1
4
9
16
25
36
49
64
81

五、回调函数

apply_async中的一个参数callback = 回调函数

回调函数:

import os
from multiprocessing import Pool

def func1(n):
    print('in func1', os.getpid())
    return n

def func2(nn):
    print('in func2', os.getpid())
    print(nn)

if __name__ == '__main__':
    print('主程序:', os.getpid())
    p = Pool(5)
    p.apply_async(func1, args=(10,), callback=func2)
    p.close()
    p.join()



主程序: 10832
in func1 12256
in func2 10832
10

代码解释:

先子进程中执行func1   在把执行了func1后的返回值传给func2作为参数。然后在主进程中执行func2

爬虫小栗子:

import requests
from multiprocessing import Pool

def get(url):
    response = requests.get(url)
    if response.status_code == 200:
        return url, response.content.decode('utf-8')

def call_back(args):
    url, content = args
    print(url,len(content))

if __name__ == '__main__':
    url_lst = [
        'https://www.cnblogs.com/',
        'http://www.baidu.com',
        'https://www.sogou.com/',
        'http://www.sohu.com/',
    ]
    p = Pool(5)
    for url in url_lst:
        p.apply_async(get,args=(url,), callback=call_back)
    p.close()
    p.join()

猜你喜欢

转载自blog.csdn.net/qq_35883464/article/details/85210267
今日推荐