前言
創(chuàng)新互聯(lián)是一家專注于成都網(wǎng)站設(shè)計(jì)、網(wǎng)站制作與策劃設(shè)計(jì),靈寶網(wǎng)站建設(shè)哪家好?創(chuàng)新互聯(lián)做網(wǎng)站,專注于網(wǎng)站建設(shè)十余年,網(wǎng)設(shè)計(jì)領(lǐng)域的專業(yè)建站公司;建站業(yè)務(wù)涵蓋:靈寶等地區(qū)。靈寶做網(wǎng)站價(jià)格咨詢:18982081108
上周“被”上線了一個(gè)緊急項(xiàng)目,周五下班接到需求,周一開始思考解決方案,周三開發(fā)完成,周四走流程上線,也算是面向領(lǐng)導(dǎo)編程了。之前的項(xiàng)目里面由于是自運(yùn)維,然后大多數(shù)又都趕時(shí)間,所以在處理定時(shí)任務(wù)上面基本都是自己在服務(wù)器上添加crontab,而不是讓多個(gè)實(shí)例自己去處理定時(shí)任務(wù)的并發(fā)鎖,并且Laravel 5.5開始自帶并發(fā)鎖,我們也快升級(jí)了。但是這次項(xiàng)目是Python項(xiàng)目,無奈只能自己實(shí)現(xiàn)一下,以下這個(gè)方案實(shí)現(xiàn)起來非常簡(jiǎn)單且易于理解。
import redis r = redis.Redis(...) last_heart = 0 # 記錄上一次得到的鎖心跳 free_lock_try = 6 # 鎖無心跳的最大次數(shù) 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: # 鎖已經(jīng)1分鐘沒有心跳了 old_heart = r.getset('mylock', 1) # 將lock重置為1,并返回set之前的心跳值 if old_heart < now_heart: time.sleep(10) continue else: break # 成功獲取到鎖,退出循環(huán) else: free_lock_try = 6 # 鎖有心跳,重置free_lock_try值 last_heart = now_heart time.sleep(10) def producer_exit(): """程序正常退出時(shí)候自動(dòng)清理鎖""" r.delete('mylock') import atexit atexit.register(producer_exit) # 業(yè)務(wù)代碼 while True: r.incr('mylock') # 讓鎖心跳加一 ...
我們來看看這段程序都解決了并發(fā)鎖中的哪些問題
導(dǎo)致Redis并發(fā)原因解釋
正所謂只有知其然才能知其所以然,只有弄明白問題出現(xiàn)的原因所在,才能對(duì)癥下藥,尋找解決問題的良方。眾所周知,Redis程序采用單線程模式進(jìn)行運(yùn)行,作為單線程程序,Redis客戶端的命令是逐條執(zhí)行,也叫做One by One執(zhí)行。既然是逐條命令執(zhí)行,從表面上來看Redis似乎不存在高并發(fā)的問題,這一觀點(diǎn)論也有道理,原子性的Redis命令本身也確實(shí)不存在高并發(fā)問題,這與多線程下的程序勃然不同。但是我們項(xiàng)目工作搭建Redis環(huán)境之后,通常都會(huì)是一組命令集合執(zhí)行程序,一個(gè)請(qǐng)求中就包含了N個(gè)Redis執(zhí)行命令,再加上多個(gè)客戶端請(qǐng)求,命令就更多了,導(dǎo)致連接超時(shí)、數(shù)據(jù)混亂或錯(cuò)誤、請(qǐng)求阻塞等多種問題。
即總結(jié)為,產(chǎn)生Redis并發(fā)誘因是程序中的業(yè)務(wù)復(fù)雜度導(dǎo)致。
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)創(chuàng)新互聯(lián)的支持。