如何使用python在redis中实现原子get或set&get密钥?

2024-05-16 16:23:47 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个redis服务器,我想实现一个原子(或伪原子)方法,它将执行以下操作(注意:我有一个与redis服务器有多个会话的系统):

  1. 如果某个键K存在,则获取该键的值
  2. 否则,用某个函数生成的随机值调用SETNX function(该函数生成salts
  3. 向redis询问keyK的值,该值是当前会话刚刚生成的(或者是由另一个会话“同时”生成的——就在当前会话生成它之前不久)

我不想用函数F预先生成一个值(在检查值是否存在之前),并在键不存在时使用它的原因是:

  1. 我不想在没有任何理由的情况下调用F(这可能会导致密集的CPU行为(
  2. 我想避免下一个问题: T1:会话1生成一个随机值VAL1 T2:第1阶段询问keyK是否存在,得到“False” T3:第2阶段生成了一个随机值VAL2 T4:第2课时询问keyK是否存在,得到“False” T5:会话2使用值VAL2调用SETNX,并从现在起使用VAL2 T6:会话1使用值VAL1调用SETNX,并从现在起使用VAL1,其中keyK的实际值是VAL2

我创建的python伪代码是:

    import redis
    r = redis.StrictRedis(host='localhost', port=6379, db=0)
    ''' gets the value of key K if exists (r.get(K) if r.exists(K)), 
    otherwise gets the value of key K if calling SETNX function returned TRUE 
    (else r.get(K) if r.setnx(K,F())), meaning this the sent value is really the value,
    otherwise, get the value of key K, that was generated by another session a         
    short moment ago (else r.get(K))
    The last one is redundant and I can write "**r.setnx(K,F()) or True**" to get the 
    latest value instead, but the syntax requires an "else" clause at the end '''
    r.get(K) if r.exists(K) else r.get(K) if r.setnx(K,F()) else r.get(K)

还有别的解决办法吗?在


Tags: ofthekey函数redisgetifvalue
1条回答
网友
1楼 · 发布于 2024-05-16 16:23:47

是的,您可以使用WATCH。下面是一个用redis-py修改的示例:

def atomic_get_set(some_key):
    with r.pipeline() as pipe:
        try:
            # put a WATCH on the key that holds our sequence value
            pipe.watch(some_key)
            # after WATCHing, the pipeline is put into immediate execution
            # mode until we tell it to start buffering commands again.
            # this allows us to get the current value of our sequence
            if pipe.exists(some_key):
                return pipe.get(some_key)
            # now we can put the pipeline back into buffered mode with MULTI
            pipe.multi()
            pipe.set(some_key, F())
            pipe.get(some_key)
            # and finally, execute the pipeline (the set and get commands)
            return pipe.execute()[-1]
            # if a WatchError wasn't raised during execution, everything
            # we just did happened atomically.
        except WatchError:
            # another client must have changed some_key between
            # the time we started WATCHing it and the pipeline's execution.
            # Let's just get the value they changed it to.
            return pipe.get(some_key)

相关问题 更多 >