1

redis で変数を更新する競合状態のない方法は次のとおりです。

r = redis.Redis()
with r.pipeline() as p:
    while 1:
        try:
            p.watch(KEY)
            val = p.get(KEY)
            newval = int(val) + 42
            p.multi()
            p.set(KEY, newval)
            p.execute()  # raises WatchError if anyone else changed KEY
            break
        except redis.WatchError:
            continue  # retry

これは、単純なバージョン (競合状態を含む) よりもかなり複雑です。

r = redis.Redis()
val = r.get(KEY)
newval = int(val) + 42
r.set(KEY, newval) 

そのため、コンテキストマネージャーを使用すると簡単に作業できると思いましたが、問題が発生しています...

私の最初のアイデアは

with update(KEY) as val:
    newval = val + 42
    somehow return newval to the contextmanager...?

最後の行を実行する明確な方法がなかったので、試してみました::

@contextmanager
def update(key, cn=None):
    """Usage::

            with update(KEY) as (p, val):
                newval = int(val) + 42
                p.set(KEY, newval)

    """
    r = cn or redis.Redis()
    with r.pipeline() as p:
        while 1:
            try:
                p.watch(key)  # --> immediate mode
                val = p.get(key)
                p.multi()  # --> back to buffered mode
                yield (p, val)
                p.execute()  # raises WatchError if anyone has changed `key`
                break  # success, break out of while loop
            except redis.WatchError:
                pass  # someone else got there before us, retry.

をキャッチしない限りうまく機能しWatchError、それから私は得る

  File "c:\python27\Lib\contextlib.py", line 28, in __exit__
    raise RuntimeError("generator didn't stop")
RuntimeError: generator didn't stop

私は何を間違っていますか?

4

1 に答える 1