2017-06-20 4 views
3

私は出力がNUMは常に10ですが、なぜスレッド名が常に同じである理由を私は知っているこの10スレッドは常に同じスレッド名を出力するのはなぜですか?

Thread-10:NUM is 10 
Thread-10:NUM is 10 
Thread-10:NUM is 10 
Thread-10:NUM is 10 
Thread-10:NUM is 10 
Thread-10:NUM is 10 
Thread-10:NUM is 10 
Thread-10:NUM is 10 
Thread-10:NUM is 10 
Thread-10:NUM is 10 

ある

NUM = 0 
def count(): 
    global NUM 
    NUM += 1 
    time.sleep(1) 
    print(t.getName()+":"+"NUM is "+str(NUM)) 

for i in range(10): 
    t = threading.Thread(target=count) 
    t.start() 

このコードを実行しましたか?すべてのスレッドはprint(t.getName()+":"+"NUM is "+str(NUM))を実行します。 tは、CPU時間を取得するスレッドであってはなりませんか?私はその名前が同じであってはならないと思う。

私は期待通りに動作します。この

NUM = 0 
def count(): 
    global NUM 
    NUM += 1 
    name = t.getName() 
    time.sleep(1) 
    print(name+":"+"NUM is "+str(NUM)) 

for i in range(10): 
    t = threading.Thread(target=count) 
    t.start() 

に変更する場合:tため

Thread-1:NUM is 10 
Thread-3:NUM is 10 
Thread-2:NUM is 10 
Thread-4:NUM is 10 
Thread-5:NUM is 10 
Thread-7:NUM is 10 
Thread-10:NUM is 10 
Thread-9:NUM is 10 
Thread-6:NUM is 10 
Thread-8:NUM is 10 
+2

't'はどこに設定されていますか? –

+0

't'は* outer *変数です。これは、例えば10に達するまで繰り返し設定されます。 –

答えて

6

これは、というグローバルの名前がtであるためです。スリープが終了するまでに、ループは終了し、tは、ループが最後に作成したスレッド(第10スレッド)にバインドされたままになります。

代わりに、結果は実際には定義されていません。そこではtを参照していますが、のループはまだ実行されているため、作成された最新のスレッドにバインドされている可能性がありますが、にはがありません。

注:現在実行中のスレッドオブジェクトへの便利なアクセスを持っていない場合、あなたはそれを得るために

threading.currentThread() 

を使用することができます。次に

threading.currentThread().getName() 

は、それを実行しているスレッドの名前を返します。あなたはこれを試して

+0

私はあなたにコードを試しましたが、実際には動作しますが、なぜ 'threading.currentThread()'を使用すると、ドキュメントは>呼び出し元の制御スレッドに対応する現在のThreadオブジェクトを返します。 't'はforループの10番目のスレッドに設定されています。 'currentThread()'は同じ10番目のスレッドであってはいけませんか? @Tim Peters – lxacoder

+1

"呼び出し元"は 'currentThread()'を呼び出すスレッドなので、あなたが意図したスレッドは常にそうです---これはスレッドの作成方法とは何の関係もありません(特に、グローバルな 't'が当時どのようなものにあっても何の関係もありません)。 –

+1

@lxacoderこのように考えてみましょう。 'count'への各呼び出しは、少なくともメインスレッドがその値を変更する前に' t' *への参照まで実行されていると仮定しています。しかし、なぜそれは必要ですか?保証される唯一のことは、各スレッドが順番に*作成されていることです。各スレッドが再び中断されるまでにどれくらいの時間が実行されるかを前提にすることはできません。 – chepner

4

あなたの機能クエリが、は何tが機能で定義されていない:

def count(): 
    global NUM 
    NUM += 1 
    name = t.getName() # use outer t 
    time.sleep(1) 
    print(name+":"+"NUM is "+str(NUM))

フォールバックメカニズムしたがって、Pythonは直接外のスコープ内でtを探します。そして、実際には、外側のスコープのtに割り当てます。その値になります。今

あなたはt急速に変化することを、forループでt = ...を書く以来。最初のスレッドが実際にtをフェッチする前に、forループが既に最後の値に達している可能性が非常に高いです(特にPythonのスレッド機構のため)。その結果、すべてのスレッドは、の最後ののスレッドを参照してtをフェッチします。

我々は、しかしに関数を書き換え場合:

NUM = 0 
def count(): 
    name = t.getName() # t fetched immediately 
    global NUM 
    NUM += 1 
    time.sleep(1) 
    print(name+":"+"NUM is "+str(NUM)) 

私が手に:私のマシンで

Thread-11:NUM is 10 
Thread-12:NUM is 10 
Thread-13:NUM is 10 
Thread-14:NUM is 10 
Thread-15:NUM is 10 
Thread-17:NUM is 10 
Thread-16:NUM is 10 
Thread-19:NUM is 10 
Thread-18:NUM is 10 
Thread-10:NUM is 10 

を。もちろんこれはではありません。は、すべてのスレッドがの正しいスレッドを取得することを保証しません。これはプロセスの後半でのみスレッドが動作し、t変数をフェッチする可能性があるためです。

+1

私はそれがなぜあなたの助けの後であるのか知っていると思います。ありがとう。 – lxacoder

+0

これは、主スレッドがスレッドを変更する前に、競合を失っている現在のスレッドのオッズが「t」にアクセスするのを確実に減らしますが、排除しません。 – chepner

+0

@chepner:ええ私は知っている、私たちはここでは異なるt値をつかむことを実証したかっただけです。しかし、私は答えの一番下にメモを追加しました。 –

2

スレッド名とカウントの両方に同じ問題があります。NUM:最初のprintステートメントを取得するまでに、10個のスレッドがすべて開始されています。 1つだけスレッドのグローバル変数tのいずれかグローバルNUMの数です。したがって、最後に表示されるのは、10番目のスレッドの値だけです。別々の値を出力したい場合は、コードを起動時に報告するためのメカニズムをコードに提供するか、反復可能なリストを保持する必要があります。

1

Iのアドバイス:

NUM = 0 
def count(): 
    global NUM 
    NUM += 1 
    num = NUM 
    name = t.getName() 
    time.sleep(1) 
    print("t.getName: " + t.getName() + ", name: " + name + ":" + ", NUM: " + str(NUM) + ", num: " + str(num)) 

for i in range(10): 
    t = threading.Thread(target=count) 
    t.start() 

結果:

t.getName: Thread-10, name: Thread-10:, NUM: 10, num: 10 
t.getName: Thread-10, name: Thread-6:, NUM: 10, num: 6 
t.getName: Thread-10, name: Thread-3:, NUM: 10, num: 3 
t.getName: Thread-10, name: Thread-5:, NUM: 10, num: 5 
t.getName: Thread-10, name: Thread-4:, NUM: 10, num: 4 
t.getName: Thread-10, name: Thread-9:, NUM: 10, num: 9 
t.getName: Thread-10, name: Thread-7:, NUM: 10, num: 7 
t.getName: Thread-10, name: Thread-2:, NUM: 10, num: 2 
t.getName: Thread-10, name: Thread-1:, NUM: 10, num: 1 
t.getName: Thread-10, name: Thread-8:, NUM: 10, num: 8 

t.getNameは()参照である関数呼び出し、です。印刷機能がコンソールに到達するまでに、tは最新のスレッドを参照します。

+0

グローバル変数と同様に、 't'は競合状態になります。特定のスレッドの関数が実際に実行されたときに、どのスレッドが参照されているのかを確認することはできません。 – chepner

関連する問題