マルチスレッドでのlist

1893 ワード

前言listはPythonでよく使われるいくつかの基本データ型の一つである.通常、listに対して追加削除と変更の操作があります.明らかに見えやすくて問題はありません.では、マルチスレッドでlistを操作してみると問題がありますか?
マルチスレッドの下のlistセキュリティor安全ではありませんか?安全じゃない!通常、スレッドセキュリティとは、あるデータ構造に対するポインタのすべての操作がスレッドセキュリティであることを意味します.この定義では、Pythonでよく使われるデータ構造list、dict、strなどはスレッドが安全ではありません.
マルチスレッド下のlistはスレッドが安全ではないがappendの操作下ではスレッドが安全である.
スレッドのセキュリティをどのように判断しますか?スレッドの安全性が安全でない場合,極端な条件で再現し,結論を導くことができる.例えばlistがスレッドが安全かどうかを判断する
Copy import threading import time
任意にcountの値を設定し、値が大きいほどエラーが速くなります.
count = 1000 l = []
def add(): for i in range(count): l.append(i) time.sleep(0.0001)
def remove():
for i in range(count):
    l.remove(i)
    time.sleep(0.0001)

t1 = threading.Thread(target=add) t2 = threading.Thread(target=remove) t1.start() t2.start() t1.join() t2.join()print(l)は、1回の実行で必ずしもエラーが発生しない場合があります.複数回再試行すると、次のようなエラーが発生します.
この操作方式には普遍性がないことは明らかで、欧州のガスが強すぎると、ずっと異常が起こらないかもしれない.
では、このような方法で、比較的簡単で効果的な方法はありませんか?答えはある
dis disライブラリはPythonが持参したライブラリであり,バイトコードの解析に利用できる.ここでは、バイトコードの各行が原子操作であり、マルチスレッド切替は原子操作単位であり、1つの操作に2行のバイトコードが必要である場合、スレッドが安全ではないことを示す認識が必要である.
removeここではまず上のlistのremove操作を見てみましょう
Copy
import dis def test_remove(): … a = [1] … a.remove(0) …
dis.dis(test_remove) 2 0 LOAD_CONST 1 (1) 2 BUILD_LIST 1 4 STORE_FAST 0 (a)
3 6 LOAD_FAST 0 (a) 8 LOAD_ATTR 0 (remove) 10 LOAD_CONST 2 (0) 12 CALL_FUNCTION 1 14 POP_TOP 16 LOAD_CONST 0 (None) 18 RETURN_VALUEは、上記からも分かるように、remove操作全体がいくつかの命令に分けられている.これは、マルチスレッドの場合にエラーが発生することを意味している.マルチスレッドの場合、removeリストをすべて削除すれば、順序に従わず、問題が発生しやすいと考えてみよう.
appendは一番上でlistのappend操作はスレッドが安全だと言いましたが、なぜでしょうか.同じようにdisで見てみましょう
Copy 8 19 LOAD_GLOBAL 0 (a) 22 LOAD_ATTR 2 (append) 25 LOAD_CONST 2 (1) 28 CALL_FUNCTION 1 31 POP_TOPここでは明らかに、appendにもいくつかの命令があり、マルチスレッド実行の場合でもインタリーブが発生するに違いないが、マルチスレッドではappendを操作する場合、listが順番に問題になることを気にしないに違いないので、appendはスレッドが安全だと言っている.