首頁  >  文章  >  資料庫  >  使用Redis鎖定處理並發問題的方法

使用Redis鎖定處理並發問題的方法

尚
轉載
2020-05-07 09:09:545985瀏覽

使用Redis鎖定處理並發問題的方法

使用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(&#39;mylock&#39;)
import atexit
atexit.register(producer_exit)

# 业务代码
while True:
  r.incr(&#39;mylock&#39;)	# 让锁心跳加一
  ...

我們來看看這段程式都解決了並發鎖定中的哪些問題:

#1、高並發下,多個進程無法同時取得到鎖定。這裡使用的是redis.setnx,如果鎖已經存在,其他程序是無法重置鎖並取得到鎖的。另外當多個進程同時發現有鎖已經沒有心跳了,使用的是redis.getset將心跳重置為1,都能set成功,但是get出來的值多個進程是不一樣的,只有真正獲取到鎖的進程回傳的是之前進程的心跳,其他進程取得到的都是1。

2、有鎖進程正常退出,可以使用atexit註冊進程退出函數刪除鎖,這裡也可以不要,不過下次啟動得等新的進程等待幾次心跳

3、有鎖進程意外退出,退出後心跳不再增加,超過free_lock_try次數後,其他進程會重新設定並取得鎖定

4、所有進程全都意外退出,這個問題不是鎖定來關心的,可以使用supervisor進行守護程式。

更多redis知識請關注redis入門教學欄位。

以上是使用Redis鎖定處理並發問題的方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:haofly。如有侵權,請聯絡admin@php.cn刪除