Python マルチタスクプログラミング - スレッド間での変数共有

関連タグ:1.Python で Web を強化
2. Shodan と Python API

問題:スレッド間でのグローバル変数データの共有エラー



import threading

g_num = 0


def task1 ():
for i in range ( 1000000 ):
global g_num
g_num += 1
print ( 'TASK1:' , g_num )

def task2 ():
for i in range ( 1000000 ):
global g_num
g_num += 1
print ( 'TASK2:' , g_num )


if __name__ == "__main__" :
first = threading.Thread ( target = task1 ) _ _
second = threading.Thread ( target = task2 ) _ _
first.start ( ) _
second.start ( ) _


実行結果:




理論上は 100 万回のループが実行され、ループごとにグローバル変数に 1 が加算されるため、最終結果は 2,000,000 になるはずです。実際の結果は上記の通りです。

原因:



2 つのスレッドが同時にグローバル変数を操作しています。スレッド 1 がグローバル変数を読み取ると同時に、スレッド 2 もグローバル変数を読み取ります。変数に対する操作を行う際、操作後の変数ではなく元の変数が読み取られます。スレッド 1 が変数操作後にコミットしていないため、スレッド 2 も操作前の変数値を読み取ってしまいます。
解決策

プロセス同期を使用して、一度に 1 つのスレッドのみがデータを操作できるようにします。

1. join() メソッドを使用する

import threading

g_num = 0


def task1 ():
for i in range ( 1000000 ):
global g_num
g_num += 1
print ( 'TASK1:' , g_num )

def task2 ():
for i in range ( 1000000 ):
global g_num
g_num += 1
print ( 'TASK2:' , g_num )


if __name__ == "__main__" :
first = threading.Thread ( target = task1 ) _ _
second = threading.Thread ( target = task2 ) _ _
first.start ( ) _
first.join ( ) _
second.start ( ) _
結果:



原理:first.join() によりプログラムの実行中に待機処理が追加され、最初の スレッドの完了後に 2 番目のスレッドが実行を開始します。これにより、同時に 1 つのスレッドのみが変数を操作することが保証されます。
スレッド同期:1 つのタスクの実行が完了した後に別のタスクを実行でき、同時に実行されるのは 1 つのタスクのみです。

2. ミューテックス

import threading

g_num = 0

# Creating a mutex is essentially a function via
LOCK = threading.Lock ( ) _
def task1 ():
# lock
LOCK.acquire ( ) _
for i in range ( 1000000 ):
global g_num
g_num += 1
print ( 'TASK1:' , g_num )
# release lock
LOCK.release ( ) _


def task2 ():
LOCK.acquire ( ) _
for i in range ( 1000000 ):
global g_num
g_num += 1
print ( 'TASK2:' , g_num )
LOCK.release ( ) _


if __name__ == "__main__" :
first = threading.Thread ( target = task1 ) _ _
second = threading.Thread ( target = task2 ) _ _
first.start ( ) _
second.start ( ) _

結果:





原理:共有データのロックにより、同時に 1 つのスレッドのみが操作を行います。複数のスレッドが同時にロックの獲得を競い、threading の Lock 関数を最初に取得したスレッドがロックを握ります。最初のスレッドの実行中、まず lock.acquire() で現在のスレッドをロックし、その間は他のスレッドが実行できません。ループ終了後、lock.release() でロックを解放すると、他のスレッドが操作可能になります。同時に同じスレッドのみが実行されることを保証します。
ただし、ミューテックスはコードの効率に一定の影響を与え、マルチタスクがシングルタスクの実行に変わるほか、ロックの解放遅延によるデッドロックの問題を引き起こす可能性があります。

著作権表示:この記事の内容は Alibaba Cloud の実名登録ユーザーによる投稿です。著作権は元の作成者に帰属します。Alibaba Cloud デベロッパーコミュニティは著作権を保有せず、相応の法的責任も負いません。詳細な規則は「Alibaba Cloud デベロッパーコミュニティユーザーサービス規約」および「Alibaba Cloud デベロッパーコミュニティ知的財産保護ガイドライン」をご参照ください。このコミュニティで盗作が疑われるコンテンツを見つけた場合は、侵害申し立てフォームに記入して報告してください。確認後、ただちに侵害が疑われるコンテンツを削除します。

関連記事

その他の特別オファーを見る

  1. Short Message Service (SMS) & Mail Service

    5 万通メールパックが USD 1.99 から、120 通の SMS が USD 1.00 から

phone お問い合わせ
Hi, I'm Alibaba Cloud AI Assistant!
I can help with questions and solutions.