日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

python使用redis_python应用中使用redis的几个思考

發(fā)布時間:2023/12/20 python 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python使用redis_python应用中使用redis的几个思考 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

使用pipeline來提高性能

應(yīng)該使用pipeline來將多個請求組合在一起,一次性在發(fā)送給服務(wù)器,并返回結(jié)果。

import redis

from redis.client import Pipeline

from typing import List

connection = redis.StrictRedis(port=16379, decode_responses=True)

pipe: Pipeline = connection.pipeline()

pipe.set(...) #1

pipe.get(...) #2

pipe.sadd(...) #3

result:List = pipe.execute()

上述代碼執(zhí)行后, #1, #2, #3的結(jié)果依次保存在數(shù)組result中。如果不使用pipeline,上述#1, #2, #3將分為三次網(wǎng)絡(luò)傳輸完成,占用3個RTT的時間,使用pipeline將使得這一時間減少到1個RTT時間。

注意pipeline只是將多個命令組合在一起發(fā)送給服務(wù)器,且結(jié)果也一次性返回,但并不意味著這些命令的執(zhí)行是原子性的。要保證其原子性,應(yīng)該使用事務(wù)。

pipeline也有美中不足的地方,就是你沒有辦法利用中間結(jié)果進行運算。比如如果#2命令依賴于#1的輸出結(jié)果,那么這兩個操作是無法pipeline在一起的。這時應(yīng)該使用客戶端腳本。

使用迭代和batch操作來提高性能

如果你要一次性地操作比如說1B的數(shù)據(jù),那么很有可能你不會有這么多內(nèi)存來存儲返回的keys,這種情況下,應(yīng)該使用scan操作。比如我們要刪除redis中的所有以user:開頭的key:

import redis

r = redis.StrictRedis(host='localhost')

for key in r.scan_iter("user:*"):

r.delete(key)

這樣內(nèi)存問題解決了,但是有點慢。

如果要一次操作很多數(shù)據(jù),比如說100k以上,應(yīng)該使用批量操作:

import redis

from itertools import izip_longest

r = redis.StrictRedis(host='localhost', port=6379, db=0)

# iterate a list in batches of size n

def batcher(iterable, n):

args = [iter(iterable)] * n

return izip_longest(*args)

# in batches of 500 delete keys matching user:*

for keybatch in batcher(r.scan_iter('user:*'),500):

r.delete(*keybatch)

這段代碼來自于Get all keys in Redis database with python,根據(jù)作者的測試,使用批量操作(且batch size為500),最高將提高5倍的速度。

需要使用asyncio嗎?

由于python的執(zhí)行是單線程的,所以在python中,一旦涉及到IO操作,我們都盡可能地使用asyncio來完成。但在訪問redis時,是否要使用asyncio,要具體分析。一般來說,我們會把redis服務(wù)器部署在離客戶端很近的地方,甚至可能就在本機,由于RTT很小,而redis本身性能很高,延時很低,因此完全可以不用異步編程模型。畢竟對redis的使用會很頻繁,python的asyncio模型中加入這么多請求后,對其調(diào)度性能也是一種考驗。兩相折沖,使用asyncio的性能并不一定高。也許這也是python下沒有特別好的asyncio模型的redis客戶端的原因。但是,上述結(jié)論是基于我們使用redis的場景是高頻,小數(shù)據(jù)量的情況。如果要與redis交換大量數(shù)據(jù),顯然還是要使用異步,以免因與redis的通信阻塞程序運行。關(guān)于這一點,我并沒有做測試,也沒有找到合適的benchmark文章。不過看到知乎文章aredis —— 一款高效的異步 redis 客戶端也有類似的觀點。

如何存儲復(fù)雜的數(shù)據(jù)結(jié)構(gòu)?

redis通過set/get, hset/hmset/hmget等命令提供了嵌套級別為0~1級的各種操作。但有時候我們需要讀寫更復(fù)雜的數(shù)據(jù)結(jié)構(gòu),我們應(yīng)該如何拓展信息嵌套的層次呢?

首先,可以使用多個數(shù)據(jù)庫來提供第一層的嵌套(或者第一級的名字空間)。這是通過建立連接時指定db索引來實現(xiàn)的:

import redis

r = redis.StrictRedis(host='localhost', port=6379, db=0)

# 通過r發(fā)生的操作都寫在db=0這個數(shù)據(jù)庫中。

redis數(shù)據(jù)庫通過整數(shù)索引,而不是更易理解的字符串名字來標識。因此,在正式的工程中,你應(yīng)該定義一些常量,通過常量名來區(qū)分各個數(shù)據(jù)庫的作用。不同的數(shù)據(jù)庫是允許存在相同的key的。現(xiàn)在,假設(shè)我們有一個CRM系統(tǒng),則相應(yīng)的用戶數(shù)據(jù),我們可以分別保存在vendor(供貨商)和customer(客戶)數(shù)據(jù)庫下。

redis提供了hash, list, set這樣的容器,從而提供了另一個級別的嵌套。比如我們的客戶數(shù)據(jù)可能組成如下:

id -> {

name: 'john',

mobile: 13400001234,

orders: [oid1, oid2, ...]

}

這樣我們可以直接通過hmset來更改用戶的名字、電話等數(shù)據(jù)。如果要操作他的訂單數(shù)據(jù)呢?當然我們可以這樣:

import redis

r = StrictRedis(...)

id = 123456 # id of user 'john'

orders = r.hget(id, orders)

# modify orders

orders.append('1111-1121')

r.hset(id, orders)

但這樣操作的效率不高,因為我們只希望給orders增加一筆訂單,沒有必要把之前的訂單數(shù)據(jù)都取回來(特別是如果用戶訂單數(shù)據(jù)很長的話,那就更是浪費)。但是redis并不提供對這一嵌套級別數(shù)據(jù)的直接操作。

有兩個辦法來解決這一問題(如何更高效地修改訂單數(shù)據(jù))。一是使用服務(wù)器腳本。或者,我們在key上做文章。比如對每一級嵌套的容器類型(hash, list, set),我們通過給它一個多級的key來將其從內(nèi)部嵌套中提取出來。以上面的用戶訂單數(shù)據(jù)為例,它是一個兩層的嵌套,超過了redis命令可以直接運算的最大深度,因此我們可以這樣改造存儲在redis中的數(shù)據(jù):

id -> {

name: 'john',

mobile: 13400001234

...

}

id:orders -> [oid1, oid2, oid3, ...]

# 還可以通過類似的方法將更深層的數(shù)據(jù)“扁平化”

創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎

總結(jié)

以上是生活随笔為你收集整理的python使用redis_python应用中使用redis的几个思考的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。