进程管道

 

进程创建注意:
*如果父进程创建对象后,创建子进程,子进程从父进程获取对象.此时父进程在对象操作上会有 一定的相互影响
例如:
套接字对象会监听相同的端口
文件对象使用同一个偏移量
*如果父进程先创建子进程,则父子进程中各自产生的对象没有任何关系

multiprocessing 模块创建进程
1.将需要执行的进程事件封装为函数
2.使用模块的process类生成进程对象,并关联相应函数
3.可以通过对象属性设置进程信息
4.启动进程,此时会自动运行绑定的函数,作为一个进程来执行

Process()
功能: 创建进程对象
参数:target 绑定的目标函数
name 给进程起名字,默认为Process-1
args 元组 给目标函数按照位置传参
kwargs 字典 给target目标函数按照键值对传参

p.start()
功能:启动进程
*target 绑定的函数开始执行,进程真正创建

p.join([timeout])
功能:阻塞等待回收进程
参数:超时时间

*使用multiprocessing创建进程,同样子进程复制父进程的全部空间代码段,
父进程执行互不影响,各自有各自的运行空间,子进程只执行对应的函数部分

*如果不使用join回收子进程则子进程会成为僵尸进程

*multiprocessing 中父进程往往只用来管理子进程的创建回收,具体事件有子进程完成


进程对象属性

p.name 进程名称
p.pid 进程pid号
p.daemon 守护进程
默认为False 表示主进程退出不会影响子进程的执行
如果设置为True 此时主进程退出子进程也会退出
* 在start 之前设置,且一般不和join一起使用
p.is_alive() 查看进程是否在生命周期


自定义进程类

1.继承Process类
2.编写自己的__init__添加自己的属性
使用super重新加载父类的__init__方法
3.重写run方法
4.使用自己的类创建进程对象
5.调用start()启动进程 此时会自动执行run方法
6.调用join()回收进程

多进程的一些问题
优点:可以使用计算机的多个内核同时运行多个任务,提高了运行效率
缺点:进程创建删除需要消耗的系统资源较多

进程池技术
产生原因:如果有大量任务需要多进程完成,则可能要频繁的创建删除进程,
此时给计算机带来的压力较大
原理:创建一定量的进程作为进程池,用来处理事件,事件处理完毕后不再销毁进程
而是继续等待处理其他的事件,直到所有待处理事件结束再统一销毁进程,增加进程的重复利用,降低资源的消耗

使用方法:
1.创建进程池,放入适当的进程
2.将要做的事件放入进程池等待队列
3.不断取事件使用进程池中进程执行,直到所有的事件处理完毕
4.关闭进程池,回收进程

from multiprocessing import Pool
pool(processes)
功能:创建进程池对象
参数:指定进程池中进程的数据量,默认根据系统自动判定

pool.apply_async(func,args,kwds)
功能:使用进程池中的进程执行相应函数
参数:func 进程事件函数
args 元组 给func按位置传参
kwds 字典 给func按键值对传参

pool.apply(func,args,kwds)
功能:使用进程池中的进程执行相应函数,一个一个执行
参数:func 进程事件函数
args 元组 给func按位置传参
kwds 字典 给func按键值对传参

pool.close()
功能: 关闭进程池,不能再添加新的事件

pool.join()
功能:阻塞等待回收进程池进程

pool.map(func,iter)
功能:将要做的事件加入进程池
参数: func 事件函数
iter 迭代对象
返回值:函数的返回值列表


进程间通讯(IPC)
原因:进程空间相对独立,资源无法互相获取,此时在不同进程间需要专门的方法进行通讯
进程间通信:管道 消息队列 共享内存 信号 信号量 套接字

通信管道(Pipe)
通信原理:在内存中开辟管道空间,生成管道操作对象,多个进程使用同一个管道对象进行读写即可实现通信

from multiprocessing import Pipe
fd1,fd2 = Pipe(duplex = True)
功能: 创建管道
参数:默认表示双向管道
如果设置为False 则为单向通道
返回值:表示管道的两端读写对象,分别管道的两端
如果是双向管道则两端都可以读写
如果是单向管道则fd1只读,fd2只写

fd.recv()
功能:从管道读取内容
返回值:读到的内容
* 当管道为空的时候则会阻塞

fd.send(data)
功能: 向管道写内容
参数:要写入的数据
* 可以写入python的数据类型

消息队列
队列:先进先出
原理:在内存中建立队列模型,进程通过队列对象将消息存入队列,或者
从队列取出消息,完成进程间的通信

from multiprocessing import Queue
q = Queue(maxsize = 0)
功能; 创建队列对象
参数:表示队列中最多存放多少个消息,不指定的话,由系统自动分配
返回值:队列对象

q.put(data,[block,timeout])
功能: 向队列存入消息
参数:data 要存入的内容 python数据
block 默认队列满时会阻塞,设置为False则为非阻塞,此时会报错
timeout 超时检测

q.get([block,timeout])
功能:从队列获取消息
参数: block 默认当队列为空时阻塞,设置为False则为非阻塞
timeout 超时检测

q.full() 判断队列是否为满
q.empty() 判断队列是否为空
q.qsize() 返回队列中消息的个数
q.close() 关闭队列

 


from multiprocessing import Pool
from time import sleep,ctime

def worker(msg):
sleep(2)
print(msg)
return ctime()

# 创建进程池
pool = Pool(processes = 3)

result = []
#向进程池添加事件
for i in range(10):
msg = 'Hello %d'%i
r = pool.apply_async(func = worker,args = (msg,))
result.append(r) # 存储函数事件
#同步执行:一个一个执行
# pool.apply(func = worker,args = (msg,))
#关闭进程池
pool.close()
#回收进程池
pool.join()
for i in result:
print(i.get()) #可以获取到进程事件函数的返回值


from multiprocessing import Process
from time import sleep

#创建带参数的进程函数
def worker(sec,name):
for i in range(3):
sleep(sec)
print("I'm %s"%name)
print("I'm working...")

# p = Process(target = worker,args = (2,'levi'))
# p = Process(target = worker,kwargs = {'sec':2,'name':'levi'})
p = Process(target = worker,args = (2,),kwargs = {'name':'levi'})
p.start()
p.join(4) #主进程只能阻塞子进程4秒,主进程的结束不会影响子进程的运行
print('============')
 
 
 
from multiprocessing import Queue,Process
import time
# 创建消息队列
q = Queue()

def fun1():
for i in range(10):
time.sleep(1)
q.put((1,2))

def fun2():
for i in range(10):
time.sleep(1.5)
a,b = q.get()
print('sum = ',a+b)

p1 = Process(target = fun1)
p2 = Process(target = fun2)

p1.start()
p2.start()
p1.join()
p2.join()



from multiprocessing import Pool
import time

def fun(n):
time.sleep(1)
return n * n

pool = Pool()

#使用map将事件放入进程池
r = pool.map(fun,[1,2,3,4,5])
print(r)
pool.close()
pool.join()






 

posted @ 2019-04-16 22:01  全宇宙第一帅  阅读(561)  评论(0编辑  收藏  举报