1

以下是在谷歌App Engine上運行一個Python瓶應用程序的一部分:谷歌應用程序引擎memcache.Client.cas()保留返回FALSE缺少關鍵

@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 

空緩存開始,如果我們做連續的GET請求/布拉布拉,我希望請求返回:

Bla 
Bla, bla 
Bla, bla, bla 
. 
. 

(如果由於某種原因在.gets()cas()緩存之間的某個點被刷新,那麼我希望的順序重新啓動,沒問題)

但是我們沒有得到任何東西,因爲memcache_client.cas()永遠會一直返回False,所以程序會卡住while -loop。顯然這是因爲密鑰'key'在開始時不存在。

我知道這一點,因爲如果我取消註釋memcache.add('key', None),它有點作品,因爲那麼密鑰存在,並且.cas()很高興並且返回True。但是,如果在.add().gets()之間的某個其他進程正好沖刷緩存,我們會回到開始的位置,並且缺少一個密鑰,並且.cas()將無限期返回False。所以這不是一個好的解決方案。

爲什麼.cas()如果密鑰在開始時丟失,就不能工作?或者至少,爲什麼.cas()接受initial_value=參數,如同其兄弟decr()?它是一個錯誤還是一個功能?我找不到這個正確記錄的任何地方,除了吉多·範羅蘇姆暗示在他single blog post on the matter -reffering到assert他做了.gets()沒有返回None,他說:

除了2:斷言有點幼稚;在實踐中,你必須以某種方式處理計數器初始化。

Dank je wel Guido-有人知道怎麼樣嗎?

回答

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是多餘的,但我寫它來說明我們要繼續嘗試,直到我們成功。

雖然在實踐中你必須以某種方式處理一些重試後放棄。