2014-12-11 4 views
5

Siehe, meinen einfachen Python Memcached Code unten:Wie atomar ein Element zu einer Memcached Liste hinzuzufügen (in 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) 

Nun, ich nehmen an, ein Element "D" auf die Liste als myList zwischengespeichert angehängt werden soll Wie kann ich das atomar machen?

Ich weiß, das ist falsch, weil es nicht atomar ist:

memcache_client.set(key, memcache_client.get(key) + ["D"]) 

Die obige Aussage enthält eine Race-Bedingung. Wenn ein anderer Thread dieselbe Anweisung zum genau richtigen Zeitpunkt ausführt, wird eines der Updates durcheinander gebracht.

Wie kann ich diese Race Condition lösen? Wie kann ich eine Liste oder ein Wörterbuch, die in memcached gespeichert sind, automatisch aktualisieren?

+0

https://code.google.com/p/memcached/wiki/NewCommands – user3159253

+0

Wahrscheinlich ist dies die Antwort, sollten Sie 'cas verwenden()' (Check-and-set) statt einfacher 'set()' – user3159253

+0

welche python memcache lib verwenden Sie? – Anentropic

Antwort

8

Hier ist die entsprechende Funktion des Python-Client-API

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

Auch hier ist ein nice tutorial von Guido van Rossum. Hoffe, er hat eine bessere Python-Sachen, als ich zu erklären;)

Hier ist, wie der Code wie in Ihrem Fall aussehen soll:

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 

Der gesamte Arbeitsablauf bleibt das gleiche: zunächst einen Wert holen (w/some Interne Informationen, die an einen Schlüssel gebunden sind), ändern dann den abgerufenen Wert und versuchen dann, ihn im Memcache zu aktualisieren. Der einzige Unterschied besteht darin, dass der Wert (tatsächlich, Schlüssel/Wert-Paar) überprüft wird, dass er nicht gleichzeitig von einem parallelen Prozess geändert wurde. Im letzteren Fall schlägt der Aufruf fehl und Sie sollten den Arbeitsablauf von Anfang an wiederholen. Wenn Sie über eine Anwendung mit mehreren Threads verfügen, sollte jede Instanz von memcache_client wahrscheinlich Thread-lokal sein.

Vergessen Sie auch nicht, dass es incr() und decr() Methoden für einfache Integer-Zähler gibt, die von Natur aus "atomar" sind.

+0

Können Sie bitte zeigen, wie ich die cas-Anweisung in meinem Fall oben verwenden sollte? Die Dokumentation enthält kein Beispiel. Wenn möglich, zeigen Sie auch, wie Sie (in Python) einen Schlüssel/Wert zu einem in memcached gespeicherten Wörterbuch hinzufügen. –

+1

note 'gets' /' cas' Syntax ist etwas anders, wenn 'pylibmc' http://sendapatch.se/projects/pylibmc/reference.html – Anentropic

-2

Wenn Sie keine Race-Bedingung erhalten möchten, müssen Sie das Lock-Primitiv aus dem Threading-Modul verwenden. Zum Beispiel

lock = threading.Lock() 

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

gibt es immer noch Race-Bedingung mit _other_ Clients des Memcache-Servers – Anentropic

+0

@Anentropic Saqib Ali hat nach Python-Threads gefragt, nicht nach mehreren Servern. Wenn er also nur einen Client mit mehreren Threads verwendet, ist meine Antwort immer noch gültig. –

Verwandte Themen