2014-12-11 22 views
5

Oto mój prosty kod Python memcached poniżej:Jak dodać element do listy memcached atomowo (w Pythonie)

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

Teraz załóżmy, że chcę dołączyć element „D” na liście w pamięci podręcznej jako myList , jak mogę to zrobić atomowo?

Wiem, że to źle, ponieważ nie jest atomowy:

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

Powyższa wypowiedź zawiera warunek wyścigu. Jeśli inny wątek wykona tę samą instrukcję dokładnie we właściwym momencie, jedna z aktualizacji zostanie zepchnięta.

Jak mogę rozwiązać ten stan wyścigu? Jak mogę zaktualizować listę lub słownik przechowywany w memcached atomowo?

+0

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

+0

Prawdopodobne jest to odpowiedź, należy użyć 'CAS()' (check-i-Set) zamiast prostych 'set()' – user3159253

+0

której używasz python memcache? – Anentropic

Odpowiedz

8

Oto odpowiednia funkcja API klienta python

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

Również tutaj znajduje się nice tutorial przez Guido van Rossum. Nadzieję, że lepiej wyjaśnić Pythona rzeczy niż ja;)

Oto jak kod powinien wyglądać w przypadku:

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 

Cały obieg pozostaje taki sam: najpierw pobrać wartość (w/niektóre wewnętrzna informacja związana z kluczem), następnie zmodyfikuj pobraną wartość, a następnie spróbuj zaktualizować ją w memcache. Jedyna różnica, że ​​wartość (właściwie para klucz/wartość) jest sprawdzona, że ​​nie została zmieniona jednocześnie z procesu równoległego. W tym drugim przypadku wywołanie nie powiedzie się i powinieneś ponowić przepływ pracy od samego początku. Ponadto, jeśli masz aplikację wielowątkową, to każda instancja memcache_client prawdopodobnie powinna być wątkowo lokalna.

Należy również pamiętać, że istnieją metody incr() i decr() dla prostych liczników całkowitych, które są z natury "atomowe".

+0

Czy możesz pokazać, jak powinienem użyć instrukcji CAS w moim przypadku powyżej? Dokumenty nie zawierają przykładu. Ponadto, jeśli to możliwe, pokaż, jak (w python) atomicznie dodać klucz/wartość do słownika przechowywanego w memcached. –

+1

Notatka Składnia 'gets' /' cas' jest nieco inna, jeśli używa się 'pylibmc' http://sendapatch.se/projects/pylibmc/reference.html – Anentropic

-2

Jeśli nie chcesz otrzymywać warunku wyścigu, musisz użyć opcji Prymityw zabezpieczający z modułu wątków. Na przykład

lock = threading.Lock() 

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

nadal występuje stan wyścigu z _innymi_ klientami serwera memcache – Anentropic

+0

@Aentrentrum Saqib Ali pytał o wątki Pythona, nie o wiele serwerów, więc jeśli użyje tylko jednego klienta z kilkoma wątkami, moja odpowiedź będzie nadal ważna. –

Powiązane problemy