python3使用python-redis-lock解決并發(fā)計算問題
需求
我在最近的一個任務(wù)中,存在一個redis高并發(fā)計算多個客戶端接收預(yù)警信息的時長問題。
模型是首先模擬多個客戶端連接預(yù)警服務(wù)器集群,然后向預(yù)警服務(wù)集群發(fā)送告警信息。隨后預(yù)警服務(wù)集群將會向客戶端推送告警信息。
此時,我記錄了發(fā)送告警至預(yù)警集群的時間,并且在客戶端還會記錄接收到告警的時間。
我將這個時間都會記錄到redis中,那么此時就會有一個問題,當(dāng)多個客戶端搶占式往redis 讀取數(shù)據(jù),計算,設(shè)置數(shù)據(jù),這個過程是會被相互覆蓋的。

可以從上面的截圖來看,多個不同的客戶端讀取redis的數(shù)據(jù),大部分讀取到了同一個數(shù)據(jù),導(dǎo)致計算錯誤。
導(dǎo)致問題的示意圖如下:

為了解決這個問題,則可以編寫一個redis的鎖,用來控制數(shù)據(jù)的并發(fā)讀取以及寫入。
在python redis庫默認(rèn)只有樂觀鎖的一種寫法,在這里我再推薦使用一個庫python-redis-lock,使用這個庫對redis多個客戶端并發(fā)的情況加鎖,真的很方便。
下面來看看怎么使用。
python-redis-lock
https://pypi.org/project/python-redis-lock/
在使用這個庫之前,需要安裝如下:
pip install python-redis-lock
使用鎖的示例:
lock = redis_lock.Lock(conn, "name-of-the-lock")
if lock.acquire(blocking=False):
print("Got the lock.")
lock.release()
else:
print("Someone else has the lock.")
上面是單獨設(shè)置鎖的方式,還可以單獨設(shè)置所有redis的操作加入鎖。
# On application start/restart import redis_lock redis_lock.reset_all(redis_client)
修改業(yè)務(wù)代碼,增加lock操作
1. 首先導(dǎo)入redis_lock
import redis_lock
2.將redis連接的客戶端傳入lock中,并設(shè)置lock的名稱
# 設(shè)置redis連接 self.conn = redis.Redis(host='127.0.0.1', port=6379, decode_responses=True, db=3) # 設(shè)置redis鎖 self.lock = redis_lock.Lock(self.conn, "redis-lock")
3.將業(yè)務(wù)讀取、設(shè)置redis的部分加入鎖
while True:
# 設(shè)置redis鎖,操作redis
if self.lock.acquire(blocking=False):
print("Got the lock.")
# 獲取lock,執(zhí)行業(yè)務(wù)處理
# 獲取當(dāng)前redis鐘記錄的客戶端接收到告警的總時長
recv_time_sum_count_clients = self.conn.get(recv_time_sum_count_clients_key)
if recv_time_sum_count_clients is None:
recv_time_sum_count_clients = "0:0"
# 獲取當(dāng)前的統(tǒng)計數(shù)據(jù)
recv_time_sum, count_clients = recv_time_sum_count_clients.split(":")
# 計算告警接收總時長
recv_time_sum = float(recv_time_sum) + recv_time
# 計算收到預(yù)警的客戶端數(shù)量
count_clients = int(count_clients) + 1
# 寫入redis中
recv_time_sum_count_clients = "%s:%s" % (str(recv_time_sum), str(count_clients))
self.conn.set(recv_time_sum_count_clients_key, recv_time_sum_count_clients)
print("user_id = %s, 計算平均時間成功, "
"recv_time_sum = %s, count_clients = %s \n" %
(self.user_id, recv_time_sum, count_clients))
# 釋放lock
self.lock.release()
# 退出循環(huán)
break
else:
print("Someone else has the lock.")
在客戶端的代碼中設(shè)置了鎖之后,再來執(zhí)行一下,看看有無搶占讀取redis數(shù)據(jù)的情況,如下:

設(shè)置了鎖之后,客戶端由于并發(fā)導(dǎo)致redis數(shù)據(jù)讀取、設(shè)置錯誤的情況就可以避免了。
并且這個庫還可以使用到Django框架中,更多細節(jié)讀者可以到該庫Github中細細查閱,本篇章就不介紹了,哈哈。
到此這篇關(guān)于python3使用python-redis-lock解決并發(fā)計算問題的文章就介紹到這了,更多相關(guān)python-redis-lock 并發(fā)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Django外鍵(ForeignKey)操作以及related_name的作用詳解
這篇文章主要介紹了Django外鍵(ForeignKey)操作以及related_name的作用詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07
詳解Python是如何實現(xiàn)issubclass的
這篇文章主要介紹了詳解Python是如何實現(xiàn)issubclass的,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07
在Linux上安裝Python的Flask框架和創(chuàng)建第一個app實例的教程
這篇文章主要介紹了在Linux上安裝Python的Flask框架和創(chuàng)建第一個app實例,包括創(chuàng)建一個HTML模版和利用Jinja2模板引擎來做渲染的步驟,需要的朋友可以參考下2015-03-03
python多線程多并發(fā)啟動appium服務(wù)的實現(xiàn)
使用Dos命令或者bat批處理來手動啟動appium服務(wù),啟動效率低下,本文主要介紹了python多線程多并發(fā)啟動appium服務(wù)的實現(xiàn),具有一定的 參考價值,感興趣的可以了解一下2024-02-02

