示例:带有自动释放特性的锁

在前面的《字符串》一章,我们曾经实现过一个锁程序,它的其中一个缺陷就是无法自行释放:如果锁的持有者因为故障下线,那么锁将一直处于持有状态,导致其他进程永远也无法获得锁。

为了解决这个问题,我们可以在获取锁的同时,通过 Redis 的自动过期特性为锁设置一个最大加锁时限,这样的话,即使锁的持有者由于故障下线,锁也会在时限到达之后自动释放。

代码清单 12-3 展示了使用上述原理实现的锁程序。


代码清单 12-3 带有自动释放特性的锁:/expire/timing_lock.py

  1. VALUE_OF_LOCK = "locking"
  2.  
  3. class TimingLock:
  4.  
  5. def __init__(self, client, key):
  6. self.client = client
  7. self.key = key
  8.  
  9. def acquire(self, timeout):
  10. """
  11. 尝试获取一个带有秒级最大使用时限的锁,
  12. 成功时返回 True ,失败时返回 False 。
  13. """
  14. result = self.client.set(self.key, VALUE_OF_LOCK, ex=timeout, nx=True)
  15. return result is not None
  16.  
  17. def release(self):
  18. """
  19. 尝试释放锁。
  20. 成功时返回 True ,失败时返回 False 。
  21. """
  22. return self.client.delete(self.key) == 1

以下代码演示了这个锁的自动释放特性:

  1. >>> from redis import Redis
  2. >>> from timing_lock import TimingLock
  3. >>> client = Redis()
  4. >>> lock = TimingLock(client, "test-lock")
  5. >>> lock.acquire(5) # 获取一个在 5 秒钟之后自动释放的锁
  6. True
  7. >>> lock.acquire(5) # 在 5 秒钟之内尝试再次获取锁,但是由于锁未被释放而失败
  8. False
  9. >>> lock.acquire(5) # 在 5 秒钟之后尝试再次获取锁
  10. True # 因为之前获取的锁已经自动被释放,所以这次将成功取得新的锁