以下是在Google App Engine上运行的Python Flask应用程序的一部分:
@app.route('/blabla', methods=['GET'])
def blabla():
# memcache.add('key', None) # this "fixes" it!
memcache_client = memcache.Client()
while True:
value = memcache_client.gets('key')
if value is None: # First time
updated_value = 'Bla'
else:
updated_value = value + ', bla'
if memcache_client.cas('key', updated_value):
return updated_value
从空缓存开始,如果我们向/ blabla发出连续的GET请求,我会希望返回请求:
Bla
Bla, bla
Bla, bla, bla
.
.
(如果出于某种原因,在.gets()
和cas()
之间的某个时刻缓存被刷新,那么我希望序列重启,没问题。)
但是我们没有得到任何东西,因为memcache_client.cas()
永远不断返回False
,所以程序卡在while
- 循环中。显然这是因为键'key'
在开头不存在。
我知道这一点,因为如果我取消对memcache.add('key', None)
的注释,那么它就会有效,因为密钥存在且.cas()
很高兴并返回True
。但是如果在.add()
和.gets()
其他进程之间正好刷新缓存,我们会回到我们开始的位置,缺少密钥,.cas()
会去无限期地返回False
。所以这不是一个好的解决方案。
如果在开头缺少密钥,为什么.cas()
不起作用?或者至少,为什么.cas()
不接受initial_value=
参数,例如它的兄弟decr()?这是一个错误还是一个功能?我无法在任何地方找到正确的文件,除了Guido van Rossum在他的single blog post on the matter中提到它 - 向assert
提出要求他使.gets()
没有返回None
他说:
除了2:断言是天真的;在实践中,你必须以某种方式处理计数器初始化。
Dank je wel Guido-有谁知道怎么样,拜托?
答案 0 :(得分:1)
好的,我明白了。
@app.route('/blabla', methods=['GET'])
def blabla():
memcache_client = memcache.Client()
while True:
if memcache.add('key', 'Bla'):
# That's all folks!
return 'Bla'
# add() failed => the key must already exist, we have to compare-and-set.
value = memcache_client.gets(key_name)
if value is None:
# At the time add() failed the key existed, but now gets() is returning None,
# so somebody must have deleted the cache entry in between.
# Let's start from scratch.
continue
updated_value = value + ', bla'
if memcache_client.cas(key_name, updated_value):
return updated_value
else:
continue
它比我希望的更复杂,但它确实有用。
最后else: continue
是多余的,但我写的是为了表明我们将继续尝试,直到我们成功。
虽然在实践中你不得不以某种方式处理经过多次重试后的放弃。