Process模块&锁&进程之间通信
# 0.同步/异步,阻塞/非阻塞-(面试)
1.涉及到IO操作时
- 同步,就是发起调用后,被调用者处理消息,必须等处理完才直接返回结果,没处理完之前是不返回的,调用者主动等待结果;
- 异步,就是发起调用后,被调用者直接返回,但是并没有返回结果,等处理完消息后,通过状态、通知或者回调函数来通知调用者,调用者被动接收结果。
2.涉及到CPU线程调度时
- 阻塞,就是调用结果返回之前,该执行线程会被挂起,不释放CPU执行权,线程不能做其它事情,只能等待,只有等到调用结果返回了,才能接着往下执行;
- 非阻塞,就是在没有获取调用结果时,不是一直等待,线程可以往下执行,如果是同步的,通过轮询的方式检查有没有调用结果返回,如果是异步的,会通知回调。
# 1. Process 模块
from multiprocessing import Process
def send_mile(*args):
print('%s发送完毕'%*args)
if __name__ == '__main__':
lis=[]
for i in range(10):
p = Process(target=send_mile,args=(1,))#args=(1,)1为传进去的参数
p.start()
lis.append(p)
for p in lis:
p.join()
print('start异步')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# 1.1守护进程
有一个参数(p.daemon())可以把一个子进程设置为守护进程
- 守护进程是随着主进程的代码结束而结束的
所有的子进程都必须在主进程结束之前结束,由主进程回收资源
import os import time from multiprocessing import Process def son(): while True: print('start') time.sleep(1) if __name__=='__main__': p=Process(target=son) p.deamon=True #把p子进程设置成了一个守护进程 p.start() time.sleep(5) print('main:')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 1.2 Process 其他方法
start() 开启进程 异步非阻塞
is_alive() 进程是否开启
terminate() 强制结束一个子进程 异步非阻塞
存在问题:在terminate告诉操作系统关闭子进程时,继续执行下面代码,强制关闭需要时间消耗,在操作系统还没来得及关闭,立即查看该子进程时还是在运行
最好的诠释了什么是异步非阻塞概念
import time
from multiprocessing import Process
def son1():
while True:
print('is alive')
time.sleep(0.5)
if __name__ == '__main__':
p = Process(target=son1)
p.start() # 异步 非阻塞
print(p.is_alive())
time.sleep(1)
p.terminate() # 异步 非阻塞
print(p.is_alive()) # 进程还活着 因为操作系统还没来得及关闭进程
time.sleep(0.01)
print(p.is_alive()) # 操作系统已经响应了我们要关闭进程的需求,再去检测的时候,得到的结果是进程已经结束了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#面试...异步非阻塞概念
**1.```涉及到IO操作时```**
- 同步,就是发起调用后,被调用者处理消息,必须等处理完才直接返回结果,没处理完之前是不返回的,调用者主动等待结果;
- 异步,就是发起调用后,被调用者直接返回,但是并没有返回结果,等处理完消息后,通过状态、通知或者回调函数来通知调用者,调用者被动接收结果。
**2.```涉及到CPU线程调度时```**
- 阻塞,就是调用结果返回之前,该执行线程会被挂起,不释放CPU执行权,线程不能做其它事情,只能等待,只有等到调用结果返回了,才能接着往下执行;
- 非阻塞,就是在没有获取调用结果时,不是一直等待,线程可以往下执行,如果是同步的,通过轮询的方式检查有没有调用结果返回,如果是异步的,会通知回调。
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 1.3 面向对象 创建子进程
#固定格式
import time
from multiprocessing import Process
class MyProcess(Process):
def __init__ (self,x,y):
self.x=x
self.y=y
super().__init__() #传参数时加上super()的init
def run(self): #gai方法的名字一定要写成run,不能变
print(self.x,self.y)
for i in range(5):
print('in son1')
time.sleep(1)
if __name__=='__main__':
mp = MyProcess(1,2) #传入参数(1,2)
mp.daemon = True
mp.start()
time.sleep(1)
print(1)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Process类汇总
# Process类
# 开启进程的方式
# 面向函数
# def 函数名:要在子进程中执行的代码
# p = Process(target= 函数名,args=(参数1,))
# 面向对象
# class 类名(Process):
# def __init__(self,参数1,参数2): # 如果子进程不需要参数可以不写
# self.a = 参数1
# self.b = 参数2
# super().__init__()
# def run(self):
# 要在子进程中执行的代码
# p = 类名(参数1,参数2)
# Process提供的操作进程的方法
# p.start() 开启进程 异步非阻塞
# p.terminate() 结束进程 异步非阻塞
# p.join() 同步阻塞
# p.isalive() 获取当前进程的状态
# daemon = True 设置为守护进程,守护进程永远在主进程的代码结束之后自动结束
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 2.锁lock
with 上下文管理
加锁之后能够保障数据的安全性,降低了代码的执行效率
with lock 给缩进下文加锁,与with open 类似,缩进内容结束后自动释放解锁
在主进程中实例化 lock=Lock()
在子进程中,对需要加锁的代码执行 with lock:
加锁应用场景:
- 操作共享的数据资源(文件,数据库)
- 对资源进行修改操作
#示例
import time
import json
from multiprocessing import Process,Lock
def buy_ticket(user,lock):
# with lock:
# lock.acquire() # 给这段代码加上一把锁
time.sleep(0.02)
with open('ticket_count') as f:
dic = json.load(f)
dic['count'] -= 1
# lock.release() # 给这段代码解锁
def task(user, lock):
with lock: #加锁最佳方式
buy_ticket(user, lock)
if __name__ == '__main__':
lock = Lock()
for i in range(10):
p = Process(target=task,args=('user%s'%i,lock))#把这把锁传递给子进程
p.start()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#了解:
with lock 与下面功能相同;
- lock.acquire() 约束,加锁
- lock.release() 释放,解锁
1
2
3
4
2
3
4
# 3.进程之间的通信 IPC
进程之间数据绝对隔离,如果通信肯定是通过文件或者网络实现通信
IPC (inter process communication)
Queue 模块
from multiprocessing import Queue
先进先出
.put() 放数据当队列为满的时候,队列会阻塞
.get() 取数据 当队列为空时,get会放生阻塞
.put_nowait() 放数据:当队列为满时,会报错,丢失数据
.get_nowait() 取数据: 当队列为空时,会报错,不阻塞
#基本格式
import queue
from multiprocessing import Queue
q = Queue(5)
q.put(1)
print(q.get())
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
Queue
使用了文件家族的 socket 和 pickle 模块
为了数据安全,也使用了 lock 模块,天生有锁,安全
pipe 管道,天生没锁了解
上次更新: 2023/04/16, 18:35:33