ホームページ  >  記事  >  バックエンド開発  >  Python では、あるスレッドによって共有変数に加えられた変更が他のスレッドから見えないのはなぜですか?

Python では、あるスレッドによって共有変数に加えられた変更が他のスレッドから見えないのはなぜですか?

WBOY
WBOY転載
2024-02-06 11:03:111182ブラウズ

为什么 Python 中一个线程对共享变量所做的更改对其他线程不可见?

質問内容

同じ変数を複数のスレッドで使用しようとしましたが、変数の値がスレッド間で一貫して更新されませんでした。たとえば、スレッド 1 が変数を 1 に更新すると、スレッド 2 はこの変更を認識せず、古い値を参照します。

これは、問題を説明する簡単なコード例です。ユーザーが「a」キーを押すと、変数「query」が更新され、次のように表示されます。

    クエリ 1: a
  1. クエリ: a
ただし、実際に得られる出力は次のとおりです:

    クエリ 1: a
これが起こっている理由とそれを修正する方法を理解するのを手伝ってもらえますか?

import getch
import threading

QUERY = ""
EXIT_THREAD = False
def input_thread():
    global EXIT_THREAD
    last_query = ""
    while not EXIT_THREAD:
        if last_query != QUERY:
            last_query = QUERY
            print(f"Query: {QUERY}")

thread = threading.Thread(target=input_thread)
thread.start()
while True:
    char = getch.getch()
    if char == "\n":
        break
    elif char == "\x7f":
        QUERY = QUERY[:-1]
    else:
        QUERY += char
    print(f"Query1: {QUERY}")
# kill input thread
EXIT_THREAD = True
thread.join()


正解


問題は、

getchモジュールのコーディングが不十分であることです。入力の待機をブロックしている間、gil (グローバル インタプリタ ロック) は解放されないため、他のスレッド は実行できません。ロックとの同期はあまり役に立ちません。gil は query へのアクセスを保護しています。 問題は、

query

を変更するたびに、ギルをロックするgetchに戻ることです。 getch が返されると、ギルがすぐに引き渡されるのに十分な時間が経過し、別のスレッドが変更をチェックし、最後の変更を確認して報告し、最終的にメインスレッドが制御を取り戻しますが、通常は getch 再度ロックするまでに十分な処理が行われていないため、別の gil スイッチが発生し、次回 getch が返されるまで、別のスレッドが実行されて変更を確認する機会が得られません。これは Python のバージョンによって異なる場合があります (Gil をチェックするルールは時々変更されます) が、常に不安定です。 正しい解決策は、ブロッキング呼び出しを行う前に

getch

モジュールが内部で gil を解放することですが、それができない場合は、gil release を呼び出すときに、各 getch に意図的にプレフィックスを付けることでこれを行うことができます。モードをブロックして他のスレッドに実行時間を与え、time モジュールをインポートし、スリープを追加して他のスレッドに最新の変更を表示する時間を与えます: リーリー これにより、期待どおりの動作が得られます。ただし、技術的には、

他の

スレッドが関与している場合は競合状態が発生しますが、このような 2 つのスレッドの場合はかなり信頼性があります。

以上がPython では、あるスレッドによって共有変数に加えられた変更が他のスレッドから見えないのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はstackoverflow.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。