互斥锁
锁在IT界都是非常重要的,不但在Python中出现,尤其是数据库中得锁更多,
比如:表锁、行锁、悲观锁、乐观锁、进程锁、互斥锁、递归锁、可重入锁、死锁等。
互斥锁是什么?
将并发变成串行 虽然牺牲了程序的执行效率 但是保证了数据的安全
互斥锁概念
同一时间运行一个进程上一把锁,就是Lock。那么我们加锁的意义在哪呢?
加锁可以保证多个进程修改同一块数据时,同一时间只能有一个任务可以进行修改,
即串行的修改。虽然我们的程序运行速度是慢了,但牺牲速度却保证了数据安全
同一时间允许多个进程上多把锁 就是[信号量Semaphore]
信号量是锁的变形:实际实现是 计数器+锁,同时允许多个进程上锁
互斥锁的作用
互斥锁Lock:互斥锁就是进程的相互排斥
谁先抢到自由,谁就上锁该资源内容,这样做可以保证数据的同步性。
注意:多个锁一起上锁,不开锁会造成死锁,上锁和释放锁是一对
什么时候使用互斥锁
多个程序同时操作一份数据的时候容易产生数据错乱
为了避免数据错乱,我们需要使用互斥锁
如何使用互斥锁
如何使用?导入模块 form multiprocessing import Process,Locklock = Lock() # 变量名创建一个锁lock.acquire() # 上锁lock.release() # 释放锁
上锁谁抢到谁使用,其他人等着使用完才能使用'''
锁相关的知识行锁:针对行数据加锁 同一时间只能一个人操作表锁:针对表数据加锁 同一时间只能一个人操作锁的应用范围很广 但是核心都是为了保证数据的安全!!!
'''
做一个简单案例试试
'简单案例'
from multiprocessing import Process,Lock
import time
'''使用锁的目的就是为了保证安全'''
def task(i,lock):lock.acquire() # 上锁print('进程%s进来了' % i)time.sleep(1)print('进程%s走了' % i)lock.release() # 释放锁'''只要上锁了,就一定别忘了最后释放锁,否则的话,别的进程永远进不来''''''加上锁就一定好吗?虽然保证了数据的安全,但是呢执行效率降低了,所以只适用于相应适配的场景,'''# 使用锁就是为了安全
if __name__ == '__main__':lock = Lock()ll = []for i in range(3):p = Process(target=task,args =(i+1,lock))p.start()ll.append(p)for j in ll:j.join()print('主线程')
模拟简易版12306抢票、查票、买票
import time, random, json
from multiprocessing import Process, Lock
import multiprocessing
# 导入模块写入系统票数
pl = {'ticket_num':5}
with open(r'data.json','w',encoding='utf-8')as f:json.dump(pl,f,ensure_ascii=False)'查票'
def search(name):with open(r'data.json','r',encoding='utf-8')as f:data = json.load(f)print(f"{name}查看票,目前剩余:{data.get('ticket_num')}")'买票'
def buy(name):# 先查询票数with open(r'data.json','r',encoding='utf-8')as f:data = json.load(f)'模拟网络延迟'time.sleep(random.randint(1,3)) #'判断当前是否有票'if data.get('ticket_num') > 0:data['ticket_num'] -= 1with open(r'data.json','w',encoding='utf-8')as f1:json.dump(data,f1,ensure_ascii=False)print(f"{name}抢票成功!")else:print(f"{name}很抱歉暂无票了")def run(name):search(name)buy(name)if __name__ == '__main__':for i in range(10):p = Process(target=run,args=(f"用户{i}",))p.start()'''这里输出结果是10个人都抢到票了,所以在这种情况下我们就得用互斥锁!'''print('============以下使用了互斥锁的代码================')'查票'
def search(name):with open(r'data.json','r',encoding='utf-8')as f:data = json.load(f)print(f"{name}正在查票,当前剩余:{data.get('ticket_num')}张票")'买票'
def buy(name):# 需要先查询是否有票with open(r'data.json','r',encoding='utf-8')as f:data = json.load(f)# 模拟延迟time.sleep(random.randint(1,3))# 判断当前是否有票if data.get('ticket_num') > 0:data['ticket_num'] -= 1with open(r'data.json','w',encoding='utf-8')as f1:json.dump(data,f1,ensure_ascii=False)print(f"用户{name},购票成功!")else:print(f"用户{name},sorry,当前暂未有票哦")def run(name,lock):search(name)# 只需要把买票环节变成串行即可lock.acquire() # 上锁buy(name)lock.release() # 释放锁if __name__ == '__main__':'互斥锁在主进程中产生一把 交给多个子进程使用''''Lock互斥锁,进程之间数据是不共享的但是Lock对象底层是通过socket来互相发送数据,不管多少进程,都是同一个Lock锁'''lock = Lock() # 创建一把锁for i in range(10):p = Process(target=run,args=(f"用户:{i}", lock))p.start()'''此时使用互斥锁就使有用户没有抢到票了'''