1

異なるスレッドからアクセスされるシングルトンがあります。このシングルトンは、ジェネレーターでデータを提供しています。ジェネレーターは、データにアクセスするスレッドによって完全に消費される必要があります。データにアクセスする各スレッドは、新しいジェネレーターを消費する必要があります。これは私のコードです:

from   datetime import datetime
import threading
import time

class MySingletonCls:

    def get_data(self, repeat):
        self.nr = 0
        for x in xrange(repeat):
            time.sleep(0.001)
            self.nr += 1
            yield x

_my_singleton = None

def MySingleton():
    global _my_singleton
    if _my_singleton == None:
        _my_singleton = MySingletonCls()
    return _my_singleton

def test_singleton():
    def worker():
        singleton = MySingleton()
        cnt = 0
        for x in singleton.get_data(100):
            cnt += 1
        print singleton.nr, cnt
    threads = []
    num_worker_threads = 5
    for i in range(num_worker_threads):
        t = threading.Thread(target=worker)
        threads.append(t)
        t.start()
    for t in threads:
        t.join()

test_singleton()

各ワーカーが 100 エントリを受け取ると予想しますが、実際はそうです。しかし、シングルトンでカウンターにアクセスすると、非常に奇妙な数値が得られます。これは私のプログラムの出力です:

457 100
468 100
470 100
471 100
475 100

ここで何が起こっているのですか?スレッドごとにシングルトン ジェネレーターを生成しているエントリの数は? シングルトン カウンターがこの奇妙な値を示しているのはなぜですか? これをスレッドセーフにするにはどうすればよいですか?

4

3 に答える 3

1

ではMySingletonCls.get_data、 はself常に同じオブジェクトを参照するためself.nr、各スレッドで同じオブジェクト スロットに名前を付けます。

つまりsingleton.nr、スレッドが開始されるたびに 0 にリセットされ、その後、スレッドごとに並行してインクリメントされます。457 から 475 までの数値が表示されているのは、最後のスレッドが開始されたときに、他のスレッドが反復を合計して 25 になったからです。

于 2012-07-08T21:00:04.440 に答える
1

シングルトンのインスタンスは 1 つしかないため、nr属性はすべてのジェネレーターで共有されます。呼び出しごとに新しいジェネレーターが作成されますが、それらはすべて同じnr属性を使用します。したがって、スレッドがジェネレーターから要素を消費するたびに が増加しnr、新しいジェネレーターが作成されるたびに がリセットされますnr。これらのインクリメントとリセットは、スレッド全体で予期せず発生しています。

各呼び出しで完全に独立したジェネレーターを生成する場合は、それらすべてを同じ属性get_dataに依存させることはできません。nrジェネレーターは各yieldで「一時停止」され、その時点での関数の状態を保持することに注意してください。そのため、属性を実際に使用する必要はまったくありません。ローカル変数を使用できます:

def get_data(self, repeat):
    nr = 0
    for x in xrange(repeat):
        time.sleep(0.001)
        nr += 1
        yield x

self.nrただし、ジェネレーターで生成しないため、とにかく何をしようとしているのかは明確ではありません。複数のスレッドがシングルトン オブジェクトを自由に変更し、それらすべてから一貫した結果を取得できるようにする方法はありません。スレッド内のアクションによってシングルトンのオブジェクトの状態が変更された場合、これらの変更がいつ発生するかはわかりません。

于 2012-07-08T21:00:21.270 に答える
0

あなたxが印刷している間、あなたは譲歩していますself.nr。新しいワーカーが生成されるたびself.nrに 0 に設定され、0 から 100 までのカウントが開始されます。

そのため、self.nrは時々リセットされ、 はselfすべてのワーカーで同じになるため、インクリメントされます(num of workers)*(100)。したがって、self.nrにリセットされた回数を考慮すると、 はそれに等しいはず0です。各「リセット」間の時間を含めて計算を行います。:D、しかし、これはあなたの問題だと思います。

于 2012-07-08T21:00:13.937 に答える