4

この引数がプログラムのメインで新しい値を取得したときに、新しいスレッドを開始してその引数を更新できるかどうか疑問に思っていたので、次のようにします。

i = 0

def foo(i):
    print i
    time.sleep(5)

thread.start_new_thread(foo,(i,))

while True:
    i = i+1

助けてくれてありがとう!

4

2 に答える 2

4

引数は、他のものと同様に単なる値です。値を渡すと、同じ値への新しい参照が作成され、その値を変更すると、すべての参照でそれが表示されます。

グローバル変数と関数パラメーターの名前が同じであることは、ここでは関係ありません。少し混乱するので、どちらかの名前を変更します。また、foo関数はそれをprint1 回だけ実行し (おそらく値をインクリメントする前に)、5 秒間スリープしてから終了します。おそらくそこにループが必要だったでしょう。そうしないと、物事が機能しているかどうかを実際に判断できません。

以下に例を示します。

i = []

def foo(j):
    while True:
        print j
        time.sleep(5)

thread.start_new_thread(foo,(i,))

while True:
    i.append(1)

では、なぜあなたのコードは機能しないのでしょうか? 値を変更しているのでi = i+1はなく、新しい値を に代入0しています。関数には、変更されていない古い値 への参照がまだあります。0 + 1ifoo0

整数は不変であるため、この問題を直接解決することはできません。しかし、間接的には非常に簡単に解決できます。整数を変更可能なある種のラッパーに置き換えます

たとえば、setおよびgetメソッドを使用して IntegerHolder クラスを作成できます。あなたi.set(i.get() + 1)と他の参照がi.get()行うと、新しい値が表示されます。

listまたは、ホルダーとして使用することもできます。リストは変更可能で、0 個以上の要素を保持します。を行うと、それは新しい整数値にi[0] = i[0] + 1置き換えられますが、それでも同じリスト値であり、それが他の参照が指しているものです。そう:i[0]i

i = [0]

def foo(j):
    print j[0]
    time.sleep(5)

thread.start_new_thread(foo,(i,))

while True:
    i[0] = i[0]+1

これは少しハックに思えるかもしれませんが、実際にはかなり一般的な Python イディオムです。


一方、別のスレッドで実行されているという事実fooは、別の問題を引き起こします。

理論的には、スレッドは同時に実行され、スレッド間のデータ アクセスの順序はありません。メイン スレッドがコア 0 で実行されi、コア 0 のキャッシュにあるコピーで作業しているときに、fooスレッドがコア 1 で実行され、コア 1 のキャッシュにある別のコピーで作業している可能i性があります。キャッシュを強制的に同期させるコード。

実際には、特に CPython では、これでうまくいくことがよくあります。しかし、いつそれを回避できるかを実際に知るには、グローバル インタープリター ロックがどのように機能するか、インタープリターが変数を処理する方法、そして (場合によっては) プラットフォームのキャッシュ コヒーレンシーや C 実装のメモリ モデルなどについても学ぶ必要があります。仕事中。ですから、それに頼ってはいけません。正しいことは、ある種の同期メカニズムを使用して へのアクセスを保護することiです。

thread補足として、 の代わりに使用することもほとんどないthreadingので、これも切り替えます。

i = []
lock = threading.Lock()

def foo(j):
    while True:
        with lock:
            print j[0]
        time.sleep(5)

t = threading.Thread(target=foo, args=(i,))
t.start()

while True:
    with lock:
        i[0] = i[0]+1

最後にもう 1 つ: スレッドを作成した場合は、join後でそれを作成する必要があります。そうしないと、きれいに終了できません。しかし、あなたのfooスレッドは決して終了しないので、それをしようとするjoinと、永久にブロックされます.

このような単純なケースには、単純な解決策があります。を呼び出す前t.start()に、実行してくださいt.daemon = True。これは、メイン スレッドが終了すると、バックグラウンド スレッドが任意の時点で自動的に強制終了されることを意味します。たとえば、ファイルやデータベースへの書き込みの場合、これは明らかに悪いことです。しかし、あなたの場合、永続的または危険なことは何もしていません。

より現実的なケースでは、通常、2 つのスレッド間でシグナルを送る何らかの方法を作成する必要があります。Queue多くの場合、スレッドが待機する何か( 、ファイル オブジェクト、またはそれらのコレクション ( 経由) など)を既に持っていますselect。そうでない場合は、ロック (または条件など適切なもの) で保護されたフラグ変数を作成するだけです。

于 2013-03-27T20:25:41.953 に答える
0

グローバルを試してください。

i = 0

def foo():
    print i
    time.sleep(5)

thread.start_new_thread(foo,())

while True:
    i = i+1

必要な変数を保持するハッシュを渡すこともできます。

args = {'i' : 0}

def foo(args):
    print args['i']
    time.sleep(5)

thread.start_new_thread(foo,(args,))

while True:
    args['i'] = arg['i'] + 1

スレッドロックを使用することもできます。

import thread

lock = thread.allocate_lock()
args = {'i' : 0}

def foo(args):
    with lock:
        print args['i']
    time.sleep(5)

thread.start_new_thread(foo,(args,))

while True:
    with lock:
        args['i'] = arg['i'] + 1

これが役に立てば幸いです。

于 2013-03-27T20:28:24.180 に答える