使用Redis鎖定處理並發問題,保證多進程僅有一個實例在運行,當運行中的實例down了後其它實例中的一個能頂上來,保證有且僅有一個實例在運行。
import redis r = redis.Redis(...) last_heart = 0 # 记录上一次得到的锁心跳 free_lock_try = 6 # 锁无心跳的最大次数 while not r.setnx('mylock', 1): now_heart = r.get('mylock') print(f"没获取到锁,now_heart={now_heart},last_heart={last_heart},free_lock_try={free_lock_try}") if now_heart == last_heart: free_lock_try = free_lock_try - 1 if free_lock_try == 0: # 锁已经1分钟没有心跳了 old_heart = r.getset('mylock', 1) # 将lock重置为1,并返回set之前的心跳值 if old_heart < now_heart: time.sleep(10) continue else: break # 成功获取到锁,退出循环 else: free_lock_try = 6 # 锁有心跳,重置free_lock_try值 last_heart = now_heart time.sleep(10) def producer_exit(): """程序正常退出时候自动清理锁""" r.delete('mylock') import atexit atexit.register(producer_exit) # 业务代码 while True: r.incr('mylock') # 让锁心跳加一 ...
我們來看看這段程式都解決了並發鎖定中的哪些問題:
#1、高並發下,多個進程無法同時取得到鎖定。這裡使用的是redis.setnx,如果鎖已經存在,其他程序是無法重置鎖並取得到鎖的。另外當多個進程同時發現有鎖已經沒有心跳了,使用的是redis.getset將心跳重置為1,都能set成功,但是get出來的值多個進程是不一樣的,只有真正獲取到鎖的進程回傳的是之前進程的心跳,其他進程取得到的都是1。
2、有鎖進程正常退出,可以使用atexit註冊進程退出函數刪除鎖,這裡也可以不要,不過下次啟動得等新的進程等待幾次心跳
3、有鎖進程意外退出,退出後心跳不再增加,超過free_lock_try次數後,其他進程會重新設定並取得鎖定
4、所有進程全都意外退出,這個問題不是鎖定來關心的,可以使用supervisor進行守護程式。
更多redis知識請關注redis入門教學欄位。
以上是使用Redis鎖定處理並發問題的方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!