2012-03-01 17 views
5

Powiedzmy mam listę l i nitki t1 iteracji po l na wiekiczy python zamrozić listę przed for-loop?

while True: 
    for i in l: 
     #do something 

i inny wątek t2 losowo zmienić lub usunąć członków w l.

Co dzieje się po usunięciu? Czy wykrywa to w bieżącej pętli t1?

UPDATE:

  1. przez zamrażanie Znaczy t1 otrzymać kopię l. t2 może modyfikować l dla pewien

  2. powołując dokumentacji lub proste, ale przekonywanie fragmencie kodu są mile widziane.

+0

Czy próbowałeś * go? –

+2

@ChrisMorgan Problemy z kondycją Race są bardzo trudne do znalezienia. Dlatego też próba ta może wykazać tylko oczywisty błąd i nie może pokazać inaczej. Co gorsza, GIL programu cpython będzie konsekwentnie ukrywać błędy. – phihag

+2

@ChrisMorgan Mam taki pomysł w moim obecnym projekcie, ale nie powoduje to błędu krytycznego i nie mogę znaleźć prostego, ale przekonującego przykładu, aby ujawnić prawdę. – onemach

Odpowiedz

7

Nie. Lista nie jest zamrożona - Twój iterator nie zostanie "przerwany" w sensie zgłaszania wyjątku. Zamiast tego będzie poruszał się dalej na liście, a wyniki mogą być zaskakujące.

Rozważmy ten kod (Snippet na ideone tutaj: http://ideone.com/0iMao):

l = list(range(10)) 
for i in l: 
    print i 
    try: 
     del l[i] 
    except (RuntimeError,IndexError), e: 
     print e 

print l 

produkuje ten wyjściowe:

0 
2 
4 
5 
7 
list assignment index out of range 
9 
list assignment index out of range 
[1, 2, 4, 5, 7, 9] 

co nie jest chyba to, co chcesz lub oczekiwane, choć jest podobno dobrze -definiowane: http://docs.python.org/reference/compound_stmts.html#the-for-statement.

Zamiast tego można zablokować listę lub wykonać kopię. Zauważ, że iter(l) nie pobiera wewnętrznej kopii, i będzie mieć taki sam efekt, jak tylko iterowanie bezpośrednio na liście.

+1

+1 za udzielenie przykładu z chill – Simon

0

lista jest dostępna z obu wątków i niezamrożona. iterator "będzie wiedział", że członkowie zostali usunięci i pominąć je, chyba że masz jawny dostęp do indeksu poza długością listy. same skreślenia są bezpieczne dla wątków.

jeśli chcesz zablokować listę, chroń ją za pomocą muteksu lub skopiuj.

2

Oto coś takiego można obserwować:

>>> from threading import Thread 
>>> from time import sleep 
>>> liszt = ['first item', 'second item', 'third item', 'fourth item', 
...   'plentee more items', "but I'm lazy"] 
>>> def thread_one(): 
...  for i in liszt: 
...    print 'Thread one found "%s"' % i 
...    sleep(1) 
... 
>>> def thread_two(): 
...  sleep(0.5) 
...  print 'Thread two deleting first item.' 
...  del liszt[0] 
...  sleep(1) 
...  print 'Thread two deleting fourth item.' 
...  del liszt[3] 
... 
>>> Thread(target=thread_one).start(); Thread(target=thread_two).start() 
Thread one found "first item" 
Thread two deleting first item. 
Thread one found "third item" 
Thread two deleting fourth item. 
Thread one found "fourth item" 
Thread one found "but I'm lazy" 

Z tego widać, że modyfikowanie listy w jednym wątku wpływa iteratora w innym wątku; usunięcie pierwszego elementu spowodowało, że iterator pominął element, usunięcie przyszłego elementu oznacza, że ​​nie będzie widoczne w iteratorze, ponieważ zniknęło.

Oto model niektórych z tego, jak to działa; Nie dostarczam tego wyraźnie, ale możesz to zrobić z obserwacji.

State:    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 
Iterator position:^

Przejdź do następnego artykułu.

State:    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 
Iterator position: ^

Usuń pierwszy element.

State:    [2, 3, 4, 5, 6, 7, 8, 9, 10] 
Iterator position: ^

Przejdź do następnego artykułu.

State:    [2, 3, 4, 5, 6, 7, 8, 9, 10] 
Iterator position:  ^

Usuń piąty element.

State:    [2, 3, 4, 5, 7, 8, 9, 10] 
Iterator position:  ^

Et cetera. W kwestii wątkowania nie ma znaczenia, czy robisz to w jednym wątku czy w wielu wątkach. Oczywiście, możesz mieć warunek wyścigu, czy przedmiot został usunięty, czy nie, ale nadal działa w ten sam sposób.

Jeśli nie znasz wewnętrznych wersji iteracji, skontaktuj się z iter. for x in y iteruje ponad iter(y), w rzeczywistości. Tak więc możesz grać z obiektem listiteratora iter(liszt), jeśli chcesz, używając next() na nim, podczas gdy grasz z listą, którą iteruje. Bardziej wygodny niż pętla for w interaktywnej konsoli Python.

Powiązane problemy