守护进程,互斥锁
守护进程
在Python中,守护进程也是一个进程,并且只能是子进程守护主进程。
了解:操作系统级别的守护进程是为了让其他进程不挂,挂了就会重启它。
默认情况下 主进程即使代码执行完毕了 也会等待子进程结束才会结束自己。
为了避免孤儿进程的产生,被守护进程(主进程)结束,守护进程(子进程)就结束
from multiprocessing import Process
import time
def task():
print("zi run")
time.sleep(3)
print("zi over")
if __name__ == '__main__':
p = Process(target=task)
p.daemon = True # 将这个进程设置为了守护进程 必须在开启进程前设置
p.start()
print("主over")
主over # 主进程结束,子进程就结束
进程安全问题
当并发的多个任务,要同时操作同一个资源,就会造成数据错乱的问题
解决方法是,将并发操作公共资源的代码由并发变为串行,牺牲效率,解决安全问题
解决方案1: join
直接使用join函数
但是用join并不完善,因为并不是全部在操作公共资源,并且这样做还不如直接串行,开进程还降低了效率
多个进程之间原本公平竞争,现在被join强行规定了顺序
解决方案2: 互斥锁
多个进程之间互相排斥的锁
-
mutex代表互斥锁
-
其原理就是将要操作公共资源的代码锁起来 以保证同一时间只能有一个进程在执行这部分代码
-
区别在于没有锁的代码,还是可以并发执行
-
锁其实只是给执行代码加了限制,本质是一个标志为True或False
from multiprocessing import Process, Lock
import time, random
def task1(mutex):
# 这里的可以并发执行
for i in range(10000):
print(1)
mutex.acquire() # 加锁
time.sleep(random.random())
print('1111111111')
time.sleep(random.random())
print('2222222222')
mutex.release() # 解锁
def task2(mutex):
for i in range(10000):
print(2)
mutex.acquire()
time.sleep(random.random())
print(444444444444)
time.sleep(random.random())
print(555555555555)
mutex.release()
if __name__ == '__main__':
mutex = Lock() # 创建一把互斥锁
print('创建锁了!!!')
p1 = Process(target=task1, args=(mutex,))
p2 = Process(target=task2, args=(mutex,))
p1.start()
p2.start()
未加锁的数字会并发打印,混乱,但是加锁的数据一定是完整打印的
如何使得即保证安全,又提高效率
锁的 粒度
粒度指的是被锁住的代码多少,被锁住的代码越多,粒度越高,效率越低
互斥锁的案例
- 抢票
from multiprocessing import Process, Lock
import json
def show():
with open('db.json', 'r', encoding='utf-8') as fr:
data = json.load(fr)
print('剩余票数', data['count'])
def buy():
with open('db.json', 'r', encoding='utf-8') as fr:
data = json.load(fr)
count = data['count']
if count > 0:
count -= 1
data['count'] = count
with open('db.json', 'w', encoding='utf-8') as fw:
json.dump(data, fw)
print('购买成功')
def task(mutex):
show()
mutex.acquire()
buy()
mutex.release()
if __name__ == '__main__':
mutex = Lock()
for i in range(7):
p = Process(target=task, args=(mutex,))
p.start()