1、创建自己的进程类
import multiprocessing as mu
import time
class ClockProcess(mu.Process):
def __init__(self, value):
self.value = value
mu.Process.__init__(self)
# 在自定义的进程类中重写父类的方法
def run(self):
n = 5
while n > 0:
print('The time is {}'.format(time.ctime()))
time.sleep(self.value)
n -= 1
# 用自己的进程类创建进程
p = ClockProcess(1)
# 自动执行run方法
p.start()
p.join()
2、多进程
优点:
并行多个任务,提高运行效率空间独立,数据安全,创建方便
缺点:
进程创建销毁的过程中消耗较多的计算机资源3、进程池
在需要频繁的创建删除较多进程的情况下,导致计算机资源消耗过多1、进程池技术如何处理
1、创建进程池,在池内放入适量的进程2、将事件加入进程池的等待队列
3、使用进程池中的进程不断处理事件
4、所有事件处理后,回收关闭进程池
2、from multiprocessing import Pool
1、Pool()
功能:创建进程池
参数:
processes : 制定进程池中进程数量
返回:
得到进程池对象
2、pool.apply_async()
功能:异步方式将事件放入进程池执行
参数:
func : 要执行的事件函数
args : 同Process中args给函数传参
kwds : 同Process中kwargs给函数传参
返回值:
返回一个对象,该对象可以通过get()方法得到func函数的返回值
3、pool.close()
功能:关闭进程池,使其无法加入新的事件
4、pool.join()
功能:阻塞等待进程池退出(当所有事件处理完毕后)
参数:
无
注:要先close,后join
示例:
from multiprocessing import Pool
import time
import os
def worker(msg):
time.sleep(2)
print(msg)
return msg + ' over'
# 创建进程池,启动4个进程
pool = Pool(processes=4)
result = []
# 放入事件
for i in range(10):
msg = 'hello %d' % i
# 加入事件后进程就会立即操作事件
# apply_async 的返回值对象,该对象可以获取worker的返回结果
r = pool.apply_async(worker, (msg,))
result.append(r)
# 关闭进程池
pool.close()
# 阻塞等待回收
pool.join()
# 通过apply_async()返回对象get()方法获取返回值
for i in result:
print(i.get())
5、pool.apply()
用法和apply_async一样,只是需要顺序执行,一个事件结束再执行另一个事件返回值:
无
6、pool.map(func,iter)
功能:类似于内建函数map 将第二个参数的迭代书传递给第一个参数的函数执行。
同时兼容了使用进程池执行
返回值:
返回func函数的返回值列表
示例:
from multiprocessing import Pool
import time
def fun(fn):
time.sleep(1)
return fn * fn
test = [1, 2, 3, 4, 5, 6]
pool = Pool(processes=4)
r = pool.map(fun, test)
# 等同于
# r=[]
# for i in test:
# res=pool.apply_async(fun,(i,))
# r.append(res.get())
print(r)
pool.close()
pool.join()
4、进程间通信
方法:
1、磁盘交互:
1、速度慢2、不安全
2、socket (已学)
本地套接字3、管道(pipe)
在内存中开辟一块空间,对多个进程可见,通过管道多进程间进行通信multiprocessing.Pipe
1、fd1,fd2=Pipe(duplex=True)
功能:创建一个进程间通信的管道
参数:
duplex默认为True 表示双向管道
设置为False 表示单项管道
返回值:
两个管道流对象,表示管道的两端
如果是双向管道则两个均可读写
如果为单项管道则fd1只能读,fd2只能写
2、fd1.recv()
功能:接收消息(每次接收一条)
参数:
无
返回值:
接收到的消息
注:如果管道内没有消息会阻塞
3、fd2.send(data)
功能:发送消息(可以是字符串或其他类型)
参数:
要发出的内容
注:如果没有接收端则管道破裂
示例:
import multiprocessing as mu
import os
import time
# 如果参数为False则fd1只能revc,fd2只能send
# fd1, fd2 = mu.Pipe()
# 创建一个双向管道
fd1, fd2 = mu.Pipe()
def fun(name):
time.sleep(1)
# 发送字符串到管道
fd1.send({'hello ' :i})
print(os.getppid(), '--------', os.getpid())
jobs = []
for i in range(5):
p = mu.Process(target=fun, args=(i,))
jobs.append(p)
p.start()
# 接收子进程发送的消息
for i in range(5):
data = fd2.recv()
print(data)
for i in jobs:
i.join()
4、消息队列
1、队列
先进先出在内存中开辟队列模型,用来存放消息,任何拥有队列的进程都可以存取消息
2、创建队列
multiprocessing.Queue()1、q=Queue(maxsize=0)
功能:
创建一个队列
参数:
maxsize 默认为0 表示队列可存放消息由内存而定
>0 表示队列最多存放多少条消息
返回值:
返回消息队列对象
2、q.put()
功能:
向队列中存放消息
参数:
要存放的消息(字符串 整数 列表)
注:当队列满时会阻塞
3、q.full()
功能:
判断队列是否为满 满返回True
4、q.get()
功能:
向队列取出消息
返回值:
取出的消息
注:当队列为空时会阻塞
5、q.empty()
功能:
判断队列是否为空,空返回True
6、q.qsize()
功能:
得到当前队列中消息的个数
注:put get中均有可选参数block和timeout
block默认为True 表示阻塞函数,如果设置为False则不阻塞
timeout block为True时,设置超时时间
示例:
from multiprocessing import Queue
# 创建队列
q = Queue(3)
q.put(1)
print(q.full())
q.put(2)
q.put(3)
print(q.full())
# 设置超时时间为3秒
q.put(4, timeout=3)
print(q.get())
print('队列中还有%d条消息' % q.qsize())
print(q.empty())
q.close() # 关闭队列
示例二
from multiprocessing import Process, Queue
import time
# 创建消息队列
q = Queue()
def fun1():
time.sleep(1)
q.put('我是进程一')
def fun2():
time.sleep(2)
print('取消息:', q.get())
p1 = Process(target=fun1)
p2 = Process(target=fun2)
p1.start()
p2.start()
p1.join()
p2.join()
3、共享内存
在内存中开辟一段空间,存储数据,对多个进程可见。每次写入内存的数据会覆盖之前的内容。
由于对内存格式化较少,所以存取速度快。
1、创建共享内存
from multiprocessing import Value, Array2、obj = Value(ctype,obj)
功能:开辟共享内存空间
参数:
ctype str 要转变的c类型 对照ctype表
obj 写入共享内存的初始值
返回值:
返回一个共享内存的对象
obj.value 即可得到共享内存中的值
示例:
from multiprocessing import Value, Process
import time
import random
# 向共享内存存钱
def deposize(money):
for i in range(100):
time.sleep(0.03)
money.value += random.randint(1, 200)
# 向共享内存取钱
def withdraw(money):
for i in range(100):
time.sleep(0.02)
money.value += random.randint(1, 150)
# 创建共享内存对象
money = Value('i', 2000)
d = Process(target=deposize, args=(money,))
w = Process(target=withdraw, args=(money,))
d.start()
w.start()
d.join()
w.join()
print(money.value)
3、obj=Array(ctype,obj)
功能:开辟共享内存空间
参数:
ctype 要转换的类型
obj 存入到共享内存中的数据
是一个列表,要求列表中数据类型一致
正整数,则表示开辟一个多大的序列空间
返回值:
返回一个共享内存对象
示例:
from multiprocessing import Array, Process
import time
def fun(shm):
for i in shm:
print(i)
shm[2] = 1000
# 开辟共享内存空间,可容纳留个整数
# 初始值是[1, 2, 3, 4, 5, 6]
# shm = Array('i', [1, 2, 3, 4, 5, 6])
#表示在共享内存中开辟一个包含6个整形的空间
shm = Array('i', 6)
p = Process(target=fun, args=(shm,))
p.start()
p.join()
for i in shm:
print(i)
管道 | 消息队列 | 共享内存 | |
---|---|---|---|
开辟空间 | 内存 | 内存 | 内存 |
读写方式 | 双向/单项 | 先进先出 | 操作覆盖内存 |
效率 | 一般 | 一般 | 快 |
应用 | 多用于亲缘进程 | 方便灵活广泛 | 较复杂 |
是否需要互斥机制 | 否 | 否 | 需要 |
4、信号
一个进程向另一个进程通过信号传递某种信息kill -l 查看信号
kill -signame PID 给PID的进程发送信号
1、关于信号:
信号名称系统定义,信号的名字
信号含义
系统定义,信号的作用
信号的默认处理方法
系统定义,信号给接收进程带来的行为,一般有 终止 暂停 忽略
2.需要记住的信
3、Python如何操作信号
1、发送:1、os.kill(pid,sig)
功能:
想一个进程发送一个信号
参数:
pid :要发送信号的进程pid
sig :要发送的信号
示例:
import os
import signal
# 向24051进程发送SIGKILL信号
os.kill(24051,signal.SIGKILL)
2、signal.alarm(sec)
功能:
向自身发送一个时钟信号 SIFALRM
参数:
sec 时钟秒数
示例
import signal
import time
# 3秒后向自己发送个SIGALRMXIN信号
signal.alarm(3)
# 阻塞等待一个信号
signal.pause()
while True:
time.sleep(1)
print('等待时钟……')
注:信号属于异步通信方式,信号的发送不会影响进程的持续执行
一个进程中只能同时有一个时钟,后面的时钟时间会覆盖前面的
2、处理:
signal.pause()
功能:
阻塞等待一个信号的发生
示例
import signal
import time
# 3秒后向自己发送个SIGALRMXIN信号
signal.alarm(3)
# 阻塞等待一个信号
signal.pause()
while True:
time.sleep(1)
print('等待时钟……')