进程锁(互斥锁)
进程锁(互斥锁)
- 由并发变成了串行,牺牲了运行效率,但避免了竞争
【1】多个进程共享同一打印终端
import time
from multiprocessing import Process, Lock
def run(i,lock):
lock.acquire()
print(f'进程{i} 正在跑')
time.sleep(2)
print(f'进程{i} 跑完')
lock.release()
if __name__ == '__main__':
lock = Lock()
for i in range(1, 5):
p = Process(target=run, args=(i,lock))
p.start()
【2】多个进程共享同一文件
- 文件当数据库,模拟抢票
- 并发运行,效率高,但竞争写同一文件,数据写入错乱
import time,os,json
from multiprocessing import Process, Lock
BASE_DIR = os.path.dirname(__file__)
file_name = 'data.json'
file_path = os.path.join(BASE_DIR, file_name)
# 初始化票数
def save_data(data=None):
if not data:
data = {'ticket_number': 2}
with open(file_path, mode='w') as fp:
json.dump(data, fp)
# 获取票数信息
def get_ticket_number():
with open(file_path, 'r') as fp:
data = json.load(fp)
return data
# 查看票数
def search_ticket_number(name):
ticket_data = get_ticket_number()
print(f'当前用户 {name} 正在查询余票 {ticket_data.get("ticket_number")} ')
# 买票
def buy_ticket(name):
# 获取票数信息
ticket_data = get_ticket_number()
ticket_number = ticket_data.get("ticket_number")
# 模拟网络延迟
time.sleep(2)
# 买票
if ticket_number > 0:
ticket_data['ticket_number'] -= 1
save_data(data=ticket_data)
print(f'当前用户 :>>>> {name} 购票成功!')
else:
print(f"当前用户 :>>>> {name} 已无余票!")
def main(name, lock):
# 查票
search_ticket_number(name=name)
# 加锁
lock.acquire()
# 买票
buy_ticket(name=name)
# 释放
lock.release()
if __name__ == '__main__':
save_data()
lock = Lock()
task_list = []
for i in range(1, 5):
process_obj = Process(target=main, args=(i, lock))
process_obj.start()
task_list.append(process_obj)
for process_obj in task_list:
process_obj.join()
# 当前用户 1 正在查询余票 2
# 当前用户 3 正在查询余票 2
# 当前用户 2 正在查询余票 2
# 当前用户 4 正在查询余票 2
# 当前用户 :>>>> 1 购票成功!
# 当前用户 :>>>> 3 购票成功!
# 当前用户 :>>>> 2 已无余票!
# 当前用户 :>>>> 4 已无余票!
【3】互斥锁的优缺点
加锁的优点
- 加锁可以保证多个进程修改同一块数据时
- 同一时间只能有一个任务可以进行修改,即串行的修改
- 没错,速度是慢了,但牺牲了速度却保证了数据安全。
加锁的缺点
- 虽然可以用文件共享数据实现进程间通信,但问题是:
- 1.效率低(共享数据基于文件,而文件是硬盘上的数据)
- 2.需要自己加锁处理
【4】行锁和表锁
行锁和表锁是数据库中常用的锁定机制。
行锁
- 行锁是在对数据库表中的某个数据行进行修改时
- 一次只允许一个用户操作该行
- 其他用户如果需要修改该行数据就必须等待。
- 通过行锁定可以避免多个用户同时修改同一行数据所导致的数据不一致问题。
表锁
- 表锁则是当一个用户操作某个数据库表时
- 会锁定整个表,其他用户同时不能操作该表。
- 这在一些特殊场景下比如表维护、备份等是非常有用的。
小结
- 总的来说
- 行锁定是比较细粒度的锁定
- 而表锁定则是更为粗粒度的锁定方法。