107

グローバル変数をスレッドと共有するにはどうすればよいですか?

私のPythonコードの例は次のとおりです。

from threading import Thread
import time
a = 0  #global variable

def thread1(threadname):
    #read variable "a" modify by thread 2

def thread2(threadname):
    while 1:
        a += 1
        time.sleep(1)

thread1 = Thread( target=thread1, args=("Thread-1", ) )
thread2 = Thread( target=thread2, args=("Thread-2", ) )

thread1.join()
thread2.join()

2 つのスレッドで 1 つの変数を共有する方法がわかりません。

4

5 に答える 5

123

その関数に対してローカルな を変更しないようaに、 でグローバルとして宣言するだけです。thread2a

def thread2(threadname):
    global a
    while True:
        a += 1
        time.sleep(1)

ではthread1、値を変更しようとしない限り、特別なことをする必要はありませんa(グローバル変数をシャドウするローカル変数が作成global aされます。必要に応じて使用してください)>

def thread1(threadname):
    #global a       # Optional if you treat a as read-only
    while a < 10:
        print a
于 2013-11-05T14:01:50.537 に答える
52

関数内:

a += 1

コンパイラによって として解釈されますがassign to a => Create local variable a、これはあなたが望むものではありません。a not initialized(ローカル) a が実際に初期化されていないため、おそらくエラーで失敗します。

>>> a = 1
>>> def f():
...     a += 1
... 
>>> f()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in f
UnboundLocalError: local variable 'a' referenced before assignment

次のように、(非常に嫌われていますが、正当な理由で)globalキーワードを使用して、必要なものを取得できます。

>>> def f():
...     global a
...     a += 1
... 
>>> a
1
>>> f()
>>> a
2

ただし、一般に、すぐに手に負えなくなるグローバル変数の使用は避けるべきです。thread1これは、いつ変更されたかを知るための同期メカニズムがないマルチスレッド プログラムに特に当てはまりますa。つまり、スレッドは複雑であり、2 つ (またはそれ以上) のスレッドが同じ値で動作する場合、イベントが発生する順序を直感的に理解することは期待できません。言語、コンパイラ、OS、プロセッサ...すべてが役割を果たすことができ、速度、実用性、またはその他の理由で操作の順序を変更することを決定できます。

この種のことの適切な方法は、Python 共有ツール (ロックとフレンド) を使用することです。または、共有する代わりにQueue を介してデータを通信することをお勧めします。たとえば、次のようにします。

from threading import Thread
from queue import Queue
import time

def thread1(threadname, q):
    #read variable "a" modify by thread 2
    while True:
        a = q.get()
        if a is None: return # Poison pill
        print a

def thread2(threadname, q):
    a = 0
    for _ in xrange(10):
        a += 1
        q.put(a)
        time.sleep(1)
    q.put(None) # Poison pill

queue = Queue()
thread1 = Thread( target=thread1, args=("Thread-1", queue) )
thread2 = Thread( target=thread2, args=("Thread-2", queue) )

thread1.start()
thread2.start()
thread1.join()
thread2.join()
于 2013-11-05T14:11:13.183 に答える
1

さて、実行例:

警告!自宅/職場では絶対にしないでください。教室のみ ;)

セマフォ、共有変数などを使用して、ラッシュ状態を回避します。

from threading import Thread
import time

a = 0  # global variable


def thread1(threadname):
    global a
    for k in range(100):
        print("{} {}".format(threadname, a))
        time.sleep(0.1)
        if k == 5:
            a += 100


def thread2(threadname):
    global a
    for k in range(10):
        a += 1
        time.sleep(0.2)


thread1 = Thread(target=thread1, args=("Thread-1",))
thread2 = Thread(target=thread2, args=("Thread-2",))

thread1.start()
thread2.start()

thread1.join()
thread2.join()

そして出力:

Thread-1 0
Thread-1 1
Thread-1 2
Thread-1 2
Thread-1 3
Thread-1 3
Thread-1 104
Thread-1 104
Thread-1 105
Thread-1 105
Thread-1 106
Thread-1 106
Thread-1 107
Thread-1 107
Thread-1 108
Thread-1 108
Thread-1 109
Thread-1 109
Thread-1 110
Thread-1 110
Thread-1 110
Thread-1 110
Thread-1 110
Thread-1 110
Thread-1 110
Thread-1 110

タイミングが正しければ、a += 100操作はスキップされます。

プロセッサは T で実行されa+100、104 を取得します。しかし、停止し、次のスレッドにジャンプしa+1ますa == 4。したがって、5 を計算します。(T+2 で) スレッド 1 に戻りa=104、メモリに書き込みます。スレッド 2 に戻ると、時間は T+3 でa=5、メモリに書き込みます。出来上がり!次の印刷命令では、104 ではなく 5 が印刷されます。

再現して捕まえる非常に厄介なバグ。

于 2018-09-26T09:45:11.630 に答える