锁/信号量/事件
1.锁
2.信号量
3.事件
1.进程锁
# -*- coding: UTF-8 -*-
"""
# @Author : yanlei
# @FileName: 进程锁.py
通过买票问题,来理解进程锁
"""
from multiprocessing import Process
import time
import json
from multiprocessing import Lock # 导入进程锁
def query(i):
with open('ticket') as f:
dic = json.load(f)
print('%s查询到余票还有 :%s 张'%(i, dic['ticket']))
def buy(i, lock):
lock.acquire() # 拿到锁 只有拿到锁的才能对数据库进行修改,数据库一次只能由一个对象进行修改
with open('ticket') as f:
dic = json.load(f)
time.sleep(0.1) # 模拟查询时的网络延迟
if dic['ticket'] > 0:
print('\033[0;31;0m %s买到票了\033[0m'%i)
dic['ticket'] -= 1
else:
print('%s没有买到票'%i)
time.sleep(0.1)
with open('ticket', 'w') as f:
json.dump(dic, f)
lock.release() # 归还锁
for i in range(10):
p = Process(target=query, args=(i, )) # 开启1买票0个查询线程,模拟并发
p.start()
# 开启10个买票线程对一张票进行购买,模拟并发
lock = Lock() # 先实例化一个锁的对象
for i in range(10):
p = Process(target=buy, args=(i, lock)) # 将锁对象一并传递给buy
p.start()
输出结果:
0查询到余票还有 :1 张
1查询到余票还有 :1 张
2查询到余票还有 :1 张
3查询到余票还有 :1 张
4查询到余票还有 :1 张
5查询到余票还有 :1 张
6查询到余票还有 :1 张
7查询到余票还有 :1 张
8查询到余票还有 :1 张
9查询到余票还有 :1 张
0买到票了
1没有买到票
2没有买到票
3没有买到票
4没有买到票
5没有买到票
6没有买到票
7没有买到票
8没有买到票
9没有买到票
#加锁可以保证多个进程修改同一块数据时,同一时间只能有一个任务可以进行修改,即串行的修改,没错,速度是慢了,但牺牲了速度却保证了数据安全。
虽然可以用文件共享数据实现进程间通信,但问题是:
1.效率低(共享数据基于文件,而文件是硬盘上的数据)
2.需要自己加锁处理
#因此我们最好找寻一种解决方案能够兼顾:1、效率高(多个进程共享一块内存的数据)2、帮我们处理好锁问题。这就是mutiprocessing模块为我们提供的基于消息的IPC通信机制:队列和管道。
队列和管道都是将数据存放于内存中
队列又是基于(管道+锁)实现的,可以让我们从复杂的锁问题中解脱出来,
我们应该尽量避免使用共享数据,尽可能使用消息传递和队列,避免处理复杂的同步和锁问题,而且在进程数目增多时,往往可以获得更好的可获展性。
2.信号量
一次只能有指定的数量的进程来操作一套资源。 相当于加了N把锁,同时有N个进程都可以取钥匙、还钥匙。
# -*- coding: UTF-8 -*-
"""
# @Author : yanlei
# @FileName: 信号量.py
"""
from multiprocessing import Process
from multiprocessing import Semaphore
import time
import random
def ktv(i, sem):
sem.acquire() # 获取钥匙
print('%s进了ktv'%i)
time.sleep(random.randint(1, 5))
print('%s走出了ktv'%i)
sem.release() # 归还钥匙
sem = Semaphore(4) # 一次只能有4个人使用这一套资源
for i in range(20):
p = Process(target=ktv, args=(i, sem))
p.start()
3.事件
e.is_set()
:查看当前是否为阻塞状态,False则为阻塞
e.wait()
:根据事件的状态决定自己是否在wait处阻塞。如果当前为阻塞,则一直等待
e.clear()
:将当前事件变成阻塞
e.set()
:将当前事件解除阻塞
from multiprocessing import Event
e = Event() # 实例化一个事件对象
# 一个事件创建之后,默认是阻塞状态
print(e.is_set()) # e.is_set() 查看当前事件是否阻塞,False为阻塞状态
e.set() # 将当前事件 解除阻塞
print(e.is_set())
e.clear()
print(e.is_set())
e.wait() # 如果当前状态为阻塞,则会一直等待
红绿灯事件
from multiprocessing import Process, Event
import random, time
def traffic_light(e):
while True:
if not e.is_set():
e.set()
print('绿灯亮')
else:
e.clear()
print('红灯亮')
time.sleep(1)
def cars(e, i):
if not e.is_set():
print('%s号车在等红灯'%i)
e.wait()
print('%s号车通行'%i)
e = Event()
traffic = Process(target=traffic_light, args=(e, ))
traffic.start()
for i in range(20):
car = Process(target=cars, args=(e, i))
car.start()
time.sleep(random.random())
网友评论