新聞中心
Redis的INT自減讓操作更容易

Redis是一個(gè)快速,開(kāi)源的鍵值內(nèi)存數(shù)據(jù)庫(kù),可用于多種應(yīng)用場(chǎng)景,例如緩存、消息隊(duì)列,等等。其中,對(duì)于計(jì)數(shù)器的管理,Redis提供了一個(gè)稱(chēng)為INCR的原子命令,該命令能夠?qū)崿F(xiàn)對(duì)計(jì)數(shù)器的自增操作。而在Redis中,還提供了一個(gè)類(lèi)似的INCR的原子命令——DECR,它能夠?qū)崿F(xiàn)對(duì)計(jì)數(shù)器的自減操作。DECR是非常有用的命令,如同INCR一樣,它也可以非常方便的實(shí)現(xiàn)某些計(jì)數(shù)器功能,如瀏覽量、訪(fǎng)問(wèn)量等場(chǎng)景,但卻經(jīng)常會(huì)被忽略。本文將講述Redis中的DECR命令,以及如何使用DECR命令實(shí)現(xiàn)一個(gè)簡(jiǎn)單的計(jì)數(shù)器,并說(shuō)明DECR的使用優(yōu)勢(shì)。
為什么DECR命令很有用?
DECR命令是一種對(duì)計(jì)數(shù)器進(jìn)行自減操作的命令。跟INCR命令相比,DECR命令并沒(méi)有得到應(yīng)有的重視,多數(shù)人對(duì)它的認(rèn)識(shí)常常停留在“不就是減一嗎”的程度。然而,在實(shí)際的開(kāi)發(fā)中,DECR命令卻具有明顯的應(yīng)用場(chǎng)景。
舉個(gè)例子,我們?cè)诰W(wǎng)站中記錄了一個(gè)帖子的閱讀量,每次有人瀏覽該帖子時(shí),就對(duì)該帖子的閱讀量進(jìn)行一次自增操作。但是在某些情況下,有一些用戶(hù)可能會(huì)手快誤點(diǎn)導(dǎo)致閱讀量的增加,而實(shí)際上并沒(méi)有真正的瀏覽該帖子。此時(shí),我們可以使用DECR命令來(lái)解決這個(gè)問(wèn)題。當(dāng)用戶(hù)誤操作時(shí),我們對(duì)閱讀量進(jìn)行一次自減操作,就能將誤操作的影響平抵掉。
示例代碼:
redis> SET views 1000
OK
redis> DECR views
(integer) 999
redis> DECR views
(integer) 998
可以看到,DECR命令需要傳入一個(gè)Redis Key作為參數(shù),該Key對(duì)應(yīng)的Value應(yīng)該是一個(gè)整數(shù)類(lèi)型,DECR命令會(huì)將該Key對(duì)應(yīng)的Value自減1。上述代碼中,我們先將一個(gè)名為views的Key的Value設(shè)置為1000,接著調(diào)用DECR命令兩次,對(duì)views的Value進(jìn)行兩次自減操作,最終的結(jié)果為998。
代碼實(shí)現(xiàn)——使用DECR命令實(shí)現(xiàn)一個(gè)延遲任務(wù)隊(duì)列
下面,我們來(lái)通過(guò)一個(gè)實(shí)例來(lái)更深入的了解DECR命令的使用,我們將使用DECR命令實(shí)現(xiàn)一個(gè)延遲任務(wù)隊(duì)列。
該延遲隊(duì)列會(huì)把需要延遲執(zhí)行的任務(wù)按照過(guò)期時(shí)間分別放入不同的Bucket中。每個(gè)Bucket存放的是任務(wù)ID,每隔指定時(shí)間查詢(xún)所有Bucket中ID,檢查時(shí)間是否過(guò)期,若過(guò)期,則將ID從Bucket中刪掉并執(zhí)行任務(wù)。
1、創(chuàng)建Bucket
我們將新建6個(gè)Bucket,分別用來(lái)存放在1秒到5秒之間、5秒到10秒之間、10秒到20秒之間、20秒到30秒之間、30秒到1分鐘之間以及長(zhǎng)于1分鐘的任務(wù)。
示例代碼:
redis-cli> MSET BUCKET1 BUCKET2 BUCKET3 BUCKET4 BUCKET5 BUCKET6
2、將任務(wù)添加到Bucket
我們將創(chuàng)建一個(gè)函數(shù)addtask來(lái)實(shí)現(xiàn)將任務(wù)添加到Bucket內(nèi)的功能。我們要在Redis中創(chuàng)建一個(gè)計(jì)數(shù)器來(lái)生成一個(gè)唯一的任務(wù)ID,我們需要實(shí)現(xiàn)將任務(wù)ID添加到對(duì)應(yīng)Bucket內(nèi)的功能。
示例代碼:
“`python
import redis
import time
conn = redis.Redis()
def addTask(task, delay):
task_id = conn.incr(“task_id”)
bucket = 0
if delay
bucket = 1
elif delay
bucket = 2
elif delay
bucket = 3
elif delay
bucket = 4
elif delay
bucket = 5
else:
return
timestamp = int(time.time() + delay)
conn.zadd(“bucket” + str(bucket), {task_id: timestamp})
return task_id
task_id = addTask(“test_task”, 5)
在addTask函數(shù)中,我們首先使用incr命令生成一個(gè)唯一的任務(wù)ID,之后根據(jù)延遲時(shí)間將任務(wù)ID添加到對(duì)應(yīng)的Bucket中。具體地,使用zadd命令將任務(wù)ID和過(guò)期時(shí)間作為參數(shù)添加到對(duì)應(yīng)Bucket的有序集合中。
同時(shí),由于我們需要多次調(diào)用Redis命令,采用創(chuàng)建Redis連接的方式來(lái)提高效率。
3、檢查任務(wù)是否過(guò)期
接下來(lái)我們要實(shí)現(xiàn)的是檢查所有Bucket中的任務(wù)ID是否過(guò)期的功能。在實(shí)現(xiàn)之前,我們需要先了解下zrangebyscore命令。該命令可以按照分?jǐn)?shù)范圍返回一個(gè)有序集合的結(jié)果,并且可以限制返回結(jié)果數(shù)量。
示例代碼:
redis-cli> ZRANGEBYSCORE BUCKET1 -inf +inf LIMIT 0 10
1) “1”
2) “2”
3) “3”
在上述代碼中,我們使用ZRANGEBYSCORE命令從Bucket1中提取所有元素,其中-inf表示無(wú)限小,+inf表示無(wú)限大,即不限定時(shí)間范圍,LIMIT 0 10表示獲取前10個(gè)元素,函數(shù)返回值為1、2、3三個(gè)元素的ID。
回到我們的檢查任務(wù)過(guò)期的功能,我們可以將過(guò)期時(shí)間的范圍設(shè)為當(dāng)前時(shí)間減去1秒到10秒之間的任務(wù),這樣可以保證不會(huì)漏掉任何一個(gè)過(guò)期的任務(wù)。
示例代碼:
```python
def checkTask():
for i in range(1, 7):
now = int(time.time())
for task_id in conn.zrangebyscore("bucket" + str(i), 0, now):
conn.zrem("bucket" + str(i), task_id)
conn.delete("task" + str(task_id))
print("task " + str(task_id) + " is done.")
在checkTask函數(shù)中,我們首先獲取當(dāng)前時(shí)間now,在每個(gè)Bucket內(nèi)查找從0到now之間的元素,若存在一個(gè)符合條件的元素,即該任務(wù)已過(guò)期,我們就將其從Bucket中刪除,并執(zhí)行相關(guān)的任務(wù),這里我們只將任務(wù)ID打印出來(lái)。
4、獲取任務(wù)
我們的程序還需要提供一個(gè)接口,供其他程序創(chuàng)建數(shù)據(jù)并將其添加到Bucket內(nèi),然后獲取過(guò)期的任務(wù)ID并執(zhí)行任務(wù)。
示例代碼:
“`python
def loopTask():
while True:
checkTask()
for i in range(1, 7):
task_ids = conn.zrangebyscore(“bucket” + str(i), 0, int(time.time()) + 10)
if len(task_ids) > 0:
tasks = {}
for task_id in task_ids:
tasks[task_id] = conn.get(“task” + str(task_id))
conn.delete(“task” + str(task_id))
conn.zrem(“bucket” + str(i), task_id)
print(tasks)
time.sleep(1)
task_id = addTask(“test_task”, 5)
print(task_id)
loopTask()
在loopTask函數(shù)中,我們首先調(diào)用checkTask函數(shù),檢查Bucket中是否有過(guò)期的任務(wù),隨后將從過(guò)期時(shí)間到當(dāng)前時(shí)間加上10s的時(shí)間范圍內(nèi)的所有任務(wù)提取出來(lái),同時(shí)將其從Bucket中刪除。我們輸出所有獲取到的任務(wù)ID和對(duì)應(yīng)的數(shù)據(jù),并在隨后的60秒內(nèi)等待新任務(wù)的到來(lái)。
結(jié)語(yǔ)
在本文中,我們?cè)敿?xì)介紹了Redis的DECR命令,并通過(guò)實(shí)現(xiàn)一個(gè)延遲任務(wù)隊(duì)列來(lái)介紹其應(yīng)用場(chǎng)景。雖然DECR命令不如INCR命令那么
成都服務(wù)器租用選創(chuàng)新互聯(lián),先試用再開(kāi)通。
創(chuàng)新互聯(lián)(www.cdcxhl.com)提供簡(jiǎn)單好用,價(jià)格厚道的香港/美國(guó)云服務(wù)器和獨(dú)立服務(wù)器。物理服務(wù)器托管租用:四川成都、綿陽(yáng)、重慶、貴陽(yáng)機(jī)房服務(wù)器托管租用。
分享文章:Redis的INT自減讓操作更容易(redis的int自減)
瀏覽路徑:http://www.dlmjj.cn/article/dphieei.html


咨詢(xún)
建站咨詢(xún)
