2014-12-11 84 views
5

看哪,下面我简单的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中的列表或字典?

+0

https://code.google.com/p/memcached/wiki/NewCommands – user3159253 2014-12-14 10:11:46

+0

很有可能这就是答案,你应该使用'CAS()'(检查和设置),而不是简单'set()' – user3159253 2014-12-14 10:12:33

+0

你正在使用哪个python memcache库? – Anentropic 2014-12-19 05:37:10

回答

8

这里的蟒蛇客户端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()方法本质上是“原子”的。

+0

你能告诉我如何在上面的例子中使用cas声明吗?该文档不包含示例。另外,如果可能的话,演示如何(在python中)以原子方式将键/值添加到存储在memcached中的字典中。 – 2014-12-14 17:49:11

+1

注意'gets' /'cas'语法略有不同,如果使用'pylibmc' http://sendapatch.se/projects/pylibmc/reference.html – Anentropic 2014-12-19 05:42:01

-2

如果您不想接收竞争条件,那么您必须使用来自线程模块的锁定原语。例如

lock = threading.Lock() 

def thread_func(): 
    obj = get_obj() 
    lock.acquire() 
    memcache_client.set(key, obj) 
    lock.release() 
+0

仍然存在竞争条件与其他_cache客户端的memcache服务器 – Anentropic 2014-12-19 05:34:42

+0

@Antropic Saqib阿里询问有关python线程不是关于多个服务器,所以如果他只用一个客户端和多个线程,我的答案仍然有效。 – 2014-12-19 10:08:50