123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101 |
- # -*- coding: utf-8 -*-
- # @Time : 2019/9/30 22:03
- # @Author : CRJ
- # @File : utils.py
- # @Software: PyCharm
- # @Python3.6
- import math
- import time
- import uuid
- import redis
- # 获取锁(乐观锁)
- def acquire_lock_with_timeout(conn, lockname, acquire_timeout=5, lock_timeout=10):
- # 128位随机标识符
- identifier = str(uuid.uuid4())
- lockname = 'lock:' + lockname
- lock_timeout = int(math.ceil(lock_timeout)) # 确保传给exprie是整数
- end = time.time() + acquire_timeout
- while time.time() < end:
- if conn.setnx(lockname, identifier):
- conn.expire(lockname, lock_timeout)
- return identifier
- elif not conn.ttl(lockname): # 为没有设置超时时间的锁设置超时时间
- conn.expire(lockname, lock_timeout)
- time.sleep(0.001)
- return False
- # 释放锁(乐观锁)
- def release_lock(conn, lockname, identifier):
- lockname = 'lock:' + lockname
- with conn.pipeline(True) as pipe:
- while True:
- try:
- pipe.watch(lockname)
- value = pipe.get(lockname)
- # 判断标志是否相同
- if value is not None and value == identifier:
- pipe.multi()
- pipe.delete(lockname)
- pipe.execute()
- return True
- # 不同则直接退出 return False
- pipe.unwatch()
- break
- except redis.exceptions.WatchError:
- pass
- return False
- class OptimisticLock:
- def __init__(self, conn, lockname, acquire_timeout=60, lock_timeout=10):
- self.conn = conn
- self.lockname = 'lock:' + lockname
- self.acquire_timeout = acquire_timeout
- self.lock_timeout = int(math.ceil(lock_timeout)) # 确保传给 expire 是整数
- self.identifier = None
- def __enter__(self):
- # 128位随机标识符
- self.identifier = str(uuid.uuid4())
- end = time.time() + self.acquire_timeout
- while time.time() < end:
- if self.conn.setnx(self.lockname, self.identifier):
- self.conn.expire(self.lockname, self.lock_timeout)
- return self
- elif not self.conn.ttl(self.lockname): # 为没有设置超时时间的锁设置超时时间
- self.conn.expire(self.lockname, self.lock_timeout)
- time.sleep(0.001)
- return self
- def __exit__(self, exc_type, exc_val, exc_tb):
- with self.conn.pipeline(True) as pipe:
- while True:
- try:
- pipe.watch(self.lockname)
- value = pipe.get(self.lockname)
- # 判断标志是否相同
- if value is not None and value == self.identifier:
- pipe.multi()
- pipe.delete(self.lockname)
- pipe.execute()
- return True
- # 不同则直接退出 return False
- pipe.unwatch()
- break
- except redis.exceptions.WatchError:
- pass
- return False
|