1、简述出现背景
Python 基于Redis实现一个简单的分布式锁
Python 基于Redis实现一个分布式可重入锁
在前面实现了简单分布式锁是用来解决分布式场景下的并发写数据问题,分布式可重入锁是用来解决并发场景下同一线程下再次或多次获得锁的问题。
那么分布式读写锁又是解决什么问题的呢?
首先来理解下概念,读写锁其实可以拆分为读锁和写锁,又称共享锁和排它锁,没错,和MySQL中的共享锁、排它锁几乎是同一个东西。那可能就有同学要问了,既然MySQL有,还用Redis实现干什么,因为Redis足够快。
它们的作用分开来讲就是:读锁允许其他读锁存在,可以进行并发的读数据。写锁会阻塞其他的读锁和写锁,在写数据时,阻塞所有读写操作,目的是尽最大的可能保证数据一致性。
2、简述原理
简述一下分布式读写锁实现原理:分为两种情况,第一种是先加了读锁,那么后面再来的读锁,都可以获得锁,不影响所有的读操作,但当出现写锁想获得锁时,就必须等读锁释放后,才能加上写锁,此时便会阻塞所有读写操作。第二种是先加了写锁,那么会阻塞所有的读写操作,直到写锁释放锁,才能被其他读锁或写锁获得锁继续向下执行。
3、代码参考
# read_write_lock.py
import time
import threading
import redis
import os, sys
class ReadWriteLock(object):
def __init__(self, cache_key, cache_type, time_out=20):
self.redis_con = self.__get_redis_con()
self.cache_key = cache_key
self.cache_type = cache_type
self.time_out = time_out
def __get_redis_con(self):
pool = redis.ConnectionPool(host='127.0.0.1',port=6379)
redis_con = redis.Redis(connection_pool=pool)
return redis_con
def get_lock(self, val):
val = val + ':' + self.cache_type
while True:
res = self.redis_con.set(self.cache_key, val, nx=True, ex=self.time_out)
if res:
# 表示获得锁成功,跳出循环
break
else:
# 此时说明已经存在数据
# 表示等待锁的过程,但是有一种情况是:如果检测到锁为读锁,来的操作也是读操作,那么不阻塞
if self.cache_type == 'read':
check_type = str(self.redis_con.get(self.cache_key).decode()).split(':')[1]
if check_type == 'read':
break
time.sleep(0.1)
def del_lock(self, val):
val = val + ':' + self.cache_type
old_val = self.redis_con.get(self.cache_key)
if old_val == val.encode():
self.redis_con.delete(self.cache_key)
SUMS = 0
def test_lock(name, num, val):
try:
if num % 2 == 0:
lock = ReadWriteLock('new_key', 'write')
else:
lock = ReadWriteLock('new_key', 'read')
print('%s 开始工作' % name)
print('%s 准备获取锁并加锁' % name)
lock.get_lock(val)
print('%s 得到锁,继续工作' % name)
global SUMS
if num % 2 == 0:
SUMS += 15
print('+++++++++++++++++++写操作++++++++++++++++')
else:
print('**********************读操作******************')
time.sleep(2)
print(SUMS)
except Exception as e:
print('发生异常:%s' % str(e))
finally:
print('%s 操作完成,准备释放锁'%name)
lock.del_lock(val)
if __name__ == '__main__':
start_time = time.time()
tasks = []
for num in range(1,4):
t = threading.Thread(target=test_lock, args=('任务%d'%num, num, 'lock%d'%num))
tasks.append(t)
t.start()
[item.join() for item in tasks]
print('总耗时:', time.time() - start_time)
4、运行测试
python read_write_lock.py
结果:
任务1 开始工作
任务1 准备获取锁并加锁
任务2 开始工作
任务2 准备获取锁并加锁
任务3 开始工作
任务3 准备获取锁并加锁
任务2 得到锁,继续工作
+++++++++++++++++++写操作++++++++++++++++
15
任务2 操作完成,准备释放锁
任务3 得到锁,继续工作
**********************读操作******************
任务1 得到锁,继续工作
**********************读操作******************
15
任务3 操作完成,准备释放锁
15
任务1 操作完成,准备释放锁
总耗时: 4.038355827331543