2012-03-01 3 views
5

は、私がリストlと永遠にlを反復処理スレッドT1を持って言う:for-loopの前にpythonはリストをフリーズしますか?

while True: 
    for i in l: 
     #do something 

、別のスレッドT2ランダムlにメンバーを変更または削除します。

削除後はどうなりますか? t1は現在のループでそれを検出しますか?

UPDATE

  1. 凍結することによって、私はT1を意味lのコピーを取得。 T2は を歓迎している 確認

  2. 引用マニュアルまたは単純だが説得コードスニペット用lを変更することができます。

+0

*試しましたか? –

+2

@ChrisMorgan競合状態のバグは悪名高く見つけにくいです。したがって、明らかにエラーがあることを示すだけで、それ以外の場合は表示されない可能性があります。さらに悪いことに、cpythonのGILは一貫してエラーを隠すでしょう。 – phihag

+2

@ChrisMorgan私は現在のプロジェクトでこれを思いついたが、これは致命的なエラーを引き起こすものではなく、真実を明らかにする簡単で説得力のある例は見つけられない。 – onemach

答えて

7

いいえリストは固定されていません。イテレータは例外を発生させる意味で「中断しません」。代わりに、それはおそらく驚くかもしれない結果で、リストを通って前進し続けるだろう。

(ここideoneでスニペット: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 

それは、この出力生成:

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

あなたが望んでいたか、期待したものはおそらくないが、それは明らかに十分であるが、定義:http://docs.python.org/reference/compound_stmts.html#the-for-statement

代わりに、リストをロックするか、コピーを取ることができます。 iter(l)は内部的にコピーを取らず、リストを直接反復するのと同じ効果があることに注意してください。ここで

+1

+1を冷やす例 – Simon

0

リストは両方のスレッドからアクセス可能であり、フリーズしません。 イテレータは、リストの長さを超えて明示的なインデックスアクセスがない限り、メンバーが削除されたことを「知っている」でしょう。 削除自体はスレッドセーフです。

リストを本当にロックしたい場合は、それをミューテックスで保護するかコピーしてください。

2

あなたが観察できるものの一種である。このことから

>>> 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" 

あなたが1つのスレッドでリストを変更すると、他のスレッドでイテレータに影響を与えていることがわかります。最初のアイテムを削除すると、イテレータはアイテムをスキップし、次のアイテムを削除すると、イテレータには表示されません。

これはいくつかの仕組みのモデルです。私はこれを明示的に提供しているわけではありませんが、あなたはこれを観測から取り除くことができます。

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

次の項目に移動します。

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

最初の項目を削除します。

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

次の項目に移動します。

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

5番目の項目を削除します。

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

等が挙げられる。スレッド化に関しては、1つのスレッドで実行するのか、複数のスレッドで実行するのかは関係ありません。確かに、アイテムが削除されているかどうかにかかわらず競合状態があるかもしれませんが、それでも同じように動作します。

あなたが繰り返しの内部に慣れていない場合は、iterを満たしています。実際にはfor x in yiter(y)を繰り返しています。したがって、あなたが望むならiter(liszt) listiteratorオブジェクトで遊ぶことができます。リスト上で反復する間にnext()を使用して再生します。インタラクティブなPythonコンソールのfor-loopよりも便利です。

関連する問題