# 进程锁
# 多个进程都操作一个数据时(下面指的是文件)、会存在数据安全问题,则需要加入锁
# 先说一个现象
# 买火车票
# 当我们手机软件买票时,发现有余票20张,但是点击订票后,告诉你票订光了
# 这是因为买票时,肯定是一个并发的过程,好多人同时来买票,并发的过程
# 当一个人订票后,我们后台肯定要修改票数,肯定是修改数据库中的剩余票数
# import json
# import time
# from multiprocessing import Process
#
# def show():
# '''
# @funcation功能:模拟查询余票
# 显示余票
# :return:
# '''
# with open('ticket', mode='r') as f: # ticket文件中的内容是{"ticket":1}这个,模拟存储的票数
# dic = json.load(f)
# print('余票:%s' % dic['ticket'])
#
# def buy_ticket(i):
# '''
# @funcation功能:模拟买票
# @param 表示谁来买票
# :return:
# '''
# with open('ticket') as f:
# dic = json.load(f)
# time.sleep(0.1) # 模拟网络延时
#
# if dic['ticket'] >= 1: # 有余票
# dic['ticket'] -= 1 # 买一张票后,就减一张票
# print('\033[32m %d 买到票了\033[0m' % i)
# else: # 没有余票了
# print('\033[31m %d 没买到票\033[0m' % i)
#
# time.sleep(0.1) # 模拟网络延时
# with open('ticket', mode='w') as f:
# json.dumps(dic, f) # 将在内存中改写的余票数,写入到文件中,模拟写入数据库的过程
#
# if __name__ == '__main__':
# # 创建5个进程,都绑定的查询余票为子进程,模拟5个人查票,此时5个人都看到有1张票
# for i in range(5):
# p = Process(target=show)
# p.start()
#
# # 5个人看到有1张票后,则都去点击买票,此时5个人都显示买到票了,也可能多个人显示买票成功了,这是有问题的,因为只有1一张票,确多个人显示买成功了
# for i in range(5):
# p = Process(target=buy_ticket, args=(i,))
# p.start()
# 解决上面举的5个人查看余票都剩1张时,5个人都去点击买票,结果系统显示多个人买票成功的问题,可以用进程锁
# 上面的问题由于操作文件的相关代码被多个人(进程)操作,
# 如果多个进程同时都去读那个文件,就会同时读到剩一张票,点击买票时,同样的多个进程同时都去加载那个文件中的剩余票数,
# 多个进程都发现有余票1张,所以多个进程就认为有余票,就买了,然后将票数减1后,多个进程又同时将余票数写入到了文件中
# 解决上面的问题思路是,每个进程不能随便的就去读那个文件与写那个文件,而是需要拿到一个锁的钥匙后才能去操作那个文件,锁和钥匙只有一个
# 当一个进程需要操作那个文件后,则拿到那个钥匙,开了锁后,进入到抽象中的屋子中,则用钥匙关闭了门,然后开始操作文件。
# 此时如果有另一个进程也要进这个屋子的时候,则必须等待前面那个人操作完了文件后,将门打开并将钥匙归还,后面的人才能操作那个文件
# 这就是进程锁的概念
import json
import time
from multiprocessing import Process
from multiprocessing import Lock # 导入进程锁模块
def show():
'''
@funcation功能:模拟查询余票
显示余票
:return:
'''
with open('ticket', mode='r') as f: # ticket文件中的内容是{"ticket":1}这个,模拟存储的票数
dic = json.load(f)
print('余票:%s' % dic['ticket'])
def buy_ticket(i, lock):
'''
@funcation功能:模拟买票
@:param 表示谁来买票
@:param 接收锁对象的参数
@:return:
'''
lock.acquire() # 如果钥匙被归还了,则拿到钥匙开锁向下执行,如果钥匙没有被归还,则阻塞在这里,等待锁被归还。 上锁
with open('ticket') as f:
dic = json.load(f)
time.sleep(0.1) # 模拟网络延时
if dic['ticket'] > 0: # 有余票
dic['ticket'] -= 1 # 买一张票后,就减一张票
print('\033[32m %s 买到票了\033[0m' % i)
else: # 没有余票了
print('\033[31m %s 没买到票\033[0m' % i)
time.sleep(0.1) # 模拟网络延时
with open('ticket', mode='w') as f:
json.dump(dic, f) # 将在内存中改写的余票数,写入到文件中,模拟写入数据库的过程
lock.release() # 归还钥匙 解锁
if __name__ == '__main__':
# 创建5个进程,都绑定的查询余票为子进程,模拟5个人查票,此时5个人都看到有1张票
for i in range(5):
p = Process(target=show)
p.start()
lock = Lock() # 得到一个锁对象
# 5个人看到有1张票后,则都去点击买票,此时每个进程都会先判断锁有没有被解开后再去买票,如果锁是上锁的则阻塞等待,先拿到钥匙的进程先买
for i in range(5):
p = Process(target=buy_ticket, args=(i, lock)) # 将锁传进去
p.start()