redis_lock.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. # -*- coding: utf-8 -*-
  2. # @Time : 2019/9/30 22:03
  3. # @Author : CRJ
  4. # @File : utils.py
  5. # @Software: PyCharm
  6. # @Python3.6
  7. import math
  8. import time
  9. import uuid
  10. import redis
  11. # 获取锁(乐观锁)
  12. def acquire_lock_with_timeout(conn, lockname, acquire_timeout=5, lock_timeout=10):
  13. # 128位随机标识符
  14. identifier = str(uuid.uuid4())
  15. lockname = 'lock:' + lockname
  16. lock_timeout = int(math.ceil(lock_timeout)) # 确保传给exprie是整数
  17. end = time.time() + acquire_timeout
  18. while time.time() < end:
  19. if conn.setnx(lockname, identifier):
  20. conn.expire(lockname, lock_timeout)
  21. return identifier
  22. elif not conn.ttl(lockname): # 为没有设置超时时间的锁设置超时时间
  23. conn.expire(lockname, lock_timeout)
  24. time.sleep(0.001)
  25. return False
  26. # 释放锁(乐观锁)
  27. def release_lock(conn, lockname, identifier):
  28. lockname = 'lock:' + lockname
  29. with conn.pipeline(True) as pipe:
  30. while True:
  31. try:
  32. pipe.watch(lockname)
  33. value = pipe.get(lockname)
  34. # 判断标志是否相同
  35. if value is not None and value == identifier:
  36. pipe.multi()
  37. pipe.delete(lockname)
  38. pipe.execute()
  39. return True
  40. # 不同则直接退出 return False
  41. pipe.unwatch()
  42. break
  43. except redis.exceptions.WatchError:
  44. pass
  45. return False
  46. class OptimisticLock:
  47. def __init__(self, conn, lockname, acquire_timeout=60, lock_timeout=10):
  48. self.conn = conn
  49. self.lockname = 'lock:' + lockname
  50. self.acquire_timeout = acquire_timeout
  51. self.lock_timeout = int(math.ceil(lock_timeout)) # 确保传给 expire 是整数
  52. self.identifier = None
  53. def __enter__(self):
  54. # 128位随机标识符
  55. self.identifier = str(uuid.uuid4())
  56. end = time.time() + self.acquire_timeout
  57. while time.time() < end:
  58. if self.conn.setnx(self.lockname, self.identifier):
  59. self.conn.expire(self.lockname, self.lock_timeout)
  60. return self
  61. elif not self.conn.ttl(self.lockname): # 为没有设置超时时间的锁设置超时时间
  62. self.conn.expire(self.lockname, self.lock_timeout)
  63. time.sleep(0.001)
  64. return self
  65. def __exit__(self, exc_type, exc_val, exc_tb):
  66. with self.conn.pipeline(True) as pipe:
  67. while True:
  68. try:
  69. pipe.watch(self.lockname)
  70. value = pipe.get(self.lockname)
  71. # 判断标志是否相同
  72. if value is not None and value == self.identifier:
  73. pipe.multi()
  74. pipe.delete(self.lockname)
  75. pipe.execute()
  76. return True
  77. # 不同则直接退出 return False
  78. pipe.unwatch()
  79. break
  80. except redis.exceptions.WatchError:
  81. pass
  82. return False