首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Python和Redis。为什么scan_iter()比带mget()的key()慢得多?

Python和Redis。为什么scan_iter()比带mget()的key()慢得多?
EN

Stack Overflow用户
提问于 2021-06-01 21:14:25
回答 1查看 4.8K关注 0票数 2

我编写了一个脚本来比较redis库中方法之间的查询速度。

据我理解,我不应该使用redis.keys(),因为它是一个阻塞函数。首选的方法是scan_iter(),它不阻塞。这事儿可以理解。但我不明白为什么scan_iter速度这么慢。

此脚本使用三种技术查询redis数据库。

  1. 使用redis.keys()获取所有键。使用redis.mget()获取所有值,
  2. 使用带有redis.scan_iter和redis.get()的for循环来获取值。(注意,我不需要键,只需要值)
  3. 使用redis.scan_iter()获取所有键。使用redis.mget()获取所有值.

备选案文1是迄今为止最快的。备选案文2的速度慢了20至30倍。备选方案3平均慢4倍。

为什么会这样呢?我是不是写错了我的代码?我有错误的方法吗?redis.keys()方法实际上是最佳选择吗?

代码语言:javascript
运行
复制
from datetime import datetime
from time import sleep
import redis
r = redis.StrictRedis(host='192.168.3.16', port=6379, decode_responses=True, db= 0)

def query_keys():
    start = datetime.now()
    redis_keys = r.keys(pattern='*')
    redis_keys = [x for x in redis_keys if not x.startswith('1_')]
    values = r.mget(redis_keys)
    end = datetime.now()
    print(str(len(values)) + ' values queried in ' + str(end - start) + ' with keys and mget.')
    
def query_scaniter():
    start = datetime.now()
    values = []
    for s in r.scan_iter():
        if not s.startswith('1_'):
            values.append(r.get(s))
    end = datetime.now()
    print(str(len(values)) + ' values queried in ' + str(end - start) + ' with scan_iter.')
    
def query_scaniter_mget():
    start = datetime.now()
    redis_keys = []
    for s in r.scan_iter():
        if not s.startswith('1_'):
            redis_keys.append(s)
    values = r.mget(redis_keys)
    end = datetime.now()
    print(str(len(values)) + ' values queried in ' + str(end - start) + ' with scan_iter and mget.')

for i in range(3):
    query_keys()
    query_scaniter()
    query_scaniter_mget()
    print('\n')
    sleep(5)

Output:
3532 values queried in 0:00:00.046872 with keys and mget.
3532 values queried in 0:00:00.781314 with scan_iter.
3532 values queried in 0:00:00.109385 with scan_iter and mget.


3526 values queried in 0:00:00.031245 with keys and mget.
3522 values queried in 0:00:00.812616 with scan_iter.
3522 values queried in 0:00:00.125007 with scan_iter and mget.


3529 values queried in 0:00:00.031246 with keys and mget.
3531 values queried in 0:00:00.797011 with scan_iter.
3530 values queried in 0:00:00.109357 with scan_iter and mget.
EN

回答 1

Stack Overflow用户

发布于 2021-06-01 23:48:11

这些结果与预期的一样。

避免KEYS的原因不是因为它太慢,而是因为它阻塞了服务器,阻止了它满足其他客户端请求。相反,SCAN一次只返回几个结果,使服务器能够保持对所有客户端的响应。

折中之处在于,执行大量SCAN调用会增加额外的开销(包括所有这些往返的网络开销)。因此,客户端的总时间将更长,但不会使服务器瘫痪,这通常是更重要的考虑因素。

请注意,如果您有大量的键,那么MGET也会有同样的问题。最可伸缩的解决方案(与最快的解决方案不同)是使用SCAN一次获得几个键,然后MGET这些键。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67796076

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档