在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
我做錯了什麼?
爲什麼不是INCRBY 42? –
因爲真正的代碼需要'newval'爲'max(float(val或'0.0')+ 7,time.time())':-) – thebjorn
這並不真正映射到上下文管理器,使用功能(見poke的答案)。 –