問題復(fù)現(xiàn)
r = redis.Redis()
lock_name = "test_lock"
r.set(lock_name, "test")
r.expire(lock_name, 1)
t1 = 0
t2 = 0
while True:
# 過期
if not r.ttl(lock_name):
# 記錄下過期的時間
if t1 == 0: t1 = time.time()
# 記錄鍵消失的時間
if not r.exists(lock_name):
t2 = time.time()
break
time.sleep(.01)
print t2 - t1
expire方法設(shè)置過期時間,ttl方法獲取過期時間(不存在則為None),按理說過期之后,鍵就會消失,即t2 - t1 應(yīng)該為0,但上面的case返回大約是0.5s。
解決方法
- 使用pttl(返回毫秒數(shù))代替ttl
- 使用StrictRedis 代替Redis
原因
首先要確認一點,這是redis-py的鍋,人家redis在某個版本之后已經(jīng)能在1毫秒以內(nèi)干掉過期的鍵了。具體是啥鍋,得好好理一理
redis正常的返回值
- 當 key 不存在時,返回 -2 。
- 當 key 存在但沒有設(shè)置剩余生存時間時,返回 -1 。
- 否則,以秒為單位,返回 key 的剩余生存時間。
- 注意 上邊以秒為單位的生存時間,在我測試后發(fā)現(xiàn)是四舍五入后的,如果時間為0.4秒則會為0
StrictRedis 和Redis 區(qū)別
- Redis 是StrictRedis 的子類,覆寫了幾個方法,大多是參數(shù)位置變一變,據(jù)說是為了兼容之前的版本所做的。
- Redis 中跟TTL 相關(guān)的是這樣一句
'TTL': lambda r: r >= 0 and r or None
,這是一個解析redis返回的方法,StrictRedis 會直接返回值,而Redis會做一次包裝。
問題就出在Redis 對redis返回的值的包裝上,lambda r: r >= 0 and r or None
我猜測他本意應(yīng)該是當對象存在ttl時返回ttl,不存在key或者沒有設(shè)置expire時返回None(即返回值為-2 或者為-1 或者返回值就是None的時候),然而因為四舍五入的存在,0.4會變?yōu)?,lambda r: r >= 0 and r or None
返回值則為None。私以為這里變?yōu)?code>lambda r: r >= 0 and r is not None or None更為合適。
綜上。