如何以原子方式将项添加到memcached列表(在Python中)

Saq*_*Ali 5 python memcached multithreading atomicity

看看下面我简单的Python memcached代码:

import memcache
memcache_client = memcache.Client(['127.0.0.1:11211'], debug=True)
key = "myList"
obj = ["A", "B", "C"]
memcache_client.set(key, obj)
Run Code Online (Sandbox Code Playgroud)

现在,假设我想将一个元素"D"附加到缓存的列表中myList,我该如何原子地执行它?

我知道这是错的,因为它不是原子的:

memcache_client.set(key, memcache_client.get(key) + ["D"])
Run Code Online (Sandbox Code Playgroud)

上述声明包含竞争条件.如果另一个线程在恰当的时刻执行同一条指令,其中一个更新将被破坏.

我怎样才能解决这种竞争条件?如何以原子方式更新存储在memcached中的列表或字典?

use*_*253 10

这是python客户端API的相应功能

https://cloud.google.com/appengine/docs/python/memcache/clientclass#Client_cas

这也是Guido van Rossum 的一个很好的教程.希望他能比我更好地解释python的东西;)

以下是代码在您的情况下的外观:

memcache_client = memcache.Client(['127.0.0.1:11211'], debug=True)
key = "myList"
while True: # Retry loop, probably it should be limited to some reasonable retries
  obj = memcache_client.gets(key)
  assert obj is not None, 'Uninitialized object'
  if memcache_client.cas(key, obj + ["D"]):
    break
Run Code Online (Sandbox Code Playgroud)

整个工作流程保持不变:首先获取一个值(带有绑定到键的一些内部信息),然后修改获取的值,然后尝试在memcache中更新它.检查值(实际上是键/值对)的唯一区别是它没有从并行进程同时更改.在后一种情况下,调用失败,您应该从头开始重试工作流.此外,如果您有一个多线程应用程序,那么每个memcache_client实例可能应该是线程本地的.

另外,不要忘记,对于简单的整数计数器,存在incr()和decr()方法,这些计数器本质上是"原子的".