如何将项目原子添加到memcached的列表(在Python)
看哪,下面我简单的Python的memcached代码:如何将项目原子添加到memcached的列表(在Python)
import memcache
memcache_client = memcache.Client(['127.0.0.1:11211'], debug=True)
key = "myList"
obj = ["A", "B", "C"]
memcache_client.set(key, obj)
现在,假设我想一个元素“d”附加到缓存为myList
列表,我怎样才能做到原子性?
我知道这是错误的,因为它不是原子:
memcache_client.set(key, memcache_client.get(key) + ["D"])
上面的语句包含的竞争条件。如果另一个线程在恰当的时刻执行这个相同的指令,其中一个更新会被破坏。
我该如何解决这种竞争条件?我如何更新以原子方式存储在memcached中的列表或字典?
这里的蟒蛇客户端API的相应功能
https://cloud.google.com/appengine/docs/python/memcache/clientclass#Client_cas
而且这里有一个nice tutorial由Guido van Rossum的。希望他最好解释蟒蛇的东西比我;)
下面的代码看起来应该像你的情况:
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
的整个工作流程是一样的:首先你取一个值(W /一些绑定到键的内部信息),然后修改获取的值,然后尝试在内存缓存中对其进行更新。唯一的区别是该值(实际上是键/值对)被检查为它没有从并行进程中同时改变。在后一种情况下,调用失败,您应该从头开始重试工作流程。另外,如果您有多线程应用程序,则每个memcache_client实例可能应该是线程本地的。
另外不要忘记,对于简单的整型计数器来说,incr()和decr()方法本质上是“原子”的。
你能告诉我如何在上面的例子中使用cas声明吗?该文档不包含示例。另外,如果可能的话,演示如何(在python中)以原子方式将键/值添加到存储在memcached中的字典中。 – 2014-12-14 17:49:11
注意'gets' /'cas'语法略有不同,如果使用'pylibmc' http://sendapatch.se/projects/pylibmc/reference.html – Anentropic 2014-12-19 05:42:01
如果您不想接收竞争条件,那么您必须使用来自线程模块的锁定原语。例如
lock = threading.Lock()
def thread_func():
obj = get_obj()
lock.acquire()
memcache_client.set(key, obj)
lock.release()
仍然存在竞争条件与其他_cache客户端的memcache服务器 – Anentropic 2014-12-19 05:34:42
@Antropic Saqib阿里询问有关python线程不是关于多个服务器,所以如果他只用一个客户端和多个线程,我的答案仍然有效。 – 2014-12-19 10:08:50
https://code.google.com/p/memcached/wiki/NewCommands – user3159253 2014-12-14 10:11:46
很有可能这就是答案,你应该使用'CAS()'(检查和设置),而不是简单'set()' – user3159253 2014-12-14 10:12:33
你正在使用哪个python memcache库? – Anentropic 2014-12-19 05:37:10