Pav*_* S. 31 time-complexity atomicity redis data-structures
是否有Redis数据结构,它允许弹出(获取+删除)多个元素的原子操作,它包含多个元素?
有众所周知的SPOP或RPOP,但它们总是返回单个值.因此,当我需要来自set/list的前N个值时,我需要调用命令N次,这很昂贵.假设集/列表包含数百万个项目.是否有类似的东西SPOPM "setName" 1000,它会返回并从集合中删除1000个随机项目,或者RPOPM "listName" 1000从列表中返回1000个最右边的项目?
我知道有像SRANDMEMBER和LRANGE这样的命令,但它们不会从数据结构中删除项目.它们可以单独删除.但是,如果有更多客户端从同一数据结构中读取,则可以多次读取一些项目,并且可以在不读取的情况下删除一些项目!因此,原子性是我的问题所在.
此外,如果这种操作的时间复杂性更昂贵,我也没关系.我怀疑它会比发布N(比如上一个例子中的1000,N)单独请求Redis服务器更昂贵.
我也知道单独的交易支持.但是,来自Redis docs的这句话不鼓励我将它用于修改集合的并行进程(从中破坏性地读取):
当使用WATCH时,EXEC只有在未修改被监视的键时才会执行命令,允许进行检查和设置机制.
tho*_*nic 12
要通过列表集合的完整示例扩展Eli的响应,使用lrange和ltrimbuiltins而不是Lua:
127.0.0.1:6379> lpush a 0 1 2 3 4 5 6 7 8 9
(integer) 10
127.0.0.1:6379> lrange a 0 3 # read 4 items off the top of the stack
1) "9"
2) "8"
3) "7"
4) "6"
127.0.0.1:6379> ltrim a 4 -1 # remove those 4 items
OK
127.0.0.1:6379> lrange a 0 999 # remaining items
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"
6) "0"
Run Code Online (Sandbox Code Playgroud)
如果你想使操作原子,你会包裹lrange和LTRIM multi和exec命令.
另外,作为其他地方所指出的,你应该ltrim在返回的项目数量没有项目的数量,你提出的要求.例如,如果你做了lrange a 0 99,但有50个项目,你会ltrim a 50 -1不会ltrim a 100 -1.
要实现队列语义而不是堆栈,请替换lpush为rpush.
从Redis 3.2开始,该命令SPOP有一个[count]参数,用于从集合中检索多个元素.
请参见http://redis.io/commands/spop#count-argument-extension
这是一个可以使用redis-py管道实现此目的的Python代码片段:
from redis import StrictRedis
client = StrictRedis()
def get_messages(q_name, prefetch_count=100):
pipe = client.pipeline()
pipe.lrange(q_name, 0, prefetch_count - 1) # Get msgs (w/o pop)
pipe.ltrim(q_name, prefetch_count, -1) # Trim (pop) list to new value
messages, trim_success = pipe.execute()
return messages
Run Code Online (Sandbox Code Playgroud)
我想我可以只做一个 for 循环,pop但这不会有效,即使使用管道,特别是如果列表队列小于prefetch_count. 如果您想查看,我在这里实现了完整的 RedisQueue 类。希望能帮助到你!