Pythonでスレッドを使用する方法
Pythonで別スレッドを起動するには、「threading
」モジュールを使用します。
import threading
新しいスレッドの実行方法
次のようにして、新しいスレッドを実行します。ただし、スレッドのメソッドは非同期(async
)指定していると動作しません。
import threading
def thread_method(param1, param2):
print(f"Thread running with {param1} and {param2}")
sub_thread = threading.Thread(target=thread_method, args=("param1", "param2"))
sub_thread.start()
このコードでは、thread_method
を別スレッドで実行し、引数として"param1"
と"param2"
を渡します。スレッドを開始するためには、start()
メソッドを呼び出します。
スレッドの終了を待つ方法
スレッドが終了するまで処理を待つ場合は、join()
メソッドを使用します。以下の例では、スレッドが完了するのを待つためにjoin()
を追加しています。
import threading
def thread_method():
for i in range(5):
print(f"Thread running")
sub_thread = threading.Thread(target=thread_method)
sub_thread.start()
print('main 1')
sub_thread.join() # スレッドが終了するまで待機
print('main 2')
出力例
Thread running
Thread running
main 1
Thread running
Thread running
Thread running
main 2
join()
メソッドを使用することで、メインスレッドはsub_thread
が完了するのを待つようになります。これにより、スレッドの実行が完了するまで次の処理に進むことがありません。
この方法は特に、スレッドの結果を使用する必要がある場合や、スレッドが完了するまで他の処理を停止させたい場合に有効です。
スレッド間で処理のバッティングを防ぐ方法
スレッド間で処理のバッティングを防ぎたい場合は、threading.Lock()
を使用します。lock
オブジェクトを利用することで、クリティカルセクション(複数のスレッドが同時にアクセスすると問題が発生する部分)へのアクセスを制御することができます。
以下は、threading.Lock()
を使用してスレッド間の処理のバッティングを防ぐ例です。
import threading
# ロックオブジェクトを作成する
lock = threading.Lock()
# 共有リソース
shared_resource = 0
def thread_method(param1):
global shared_resource
# ロックを取得
with lock:
# クリティカルセクション
print(f"Thread {param1} is running")
shared_resource += 1
print(f"Shared resource value: {shared_resource}")
# スレッドを作成して起動する
threads = []
for i in range(5):
thread = threading.Thread(target=thread_method, args=(i,))
threads.append(thread)
thread.start()
# 全てのスレッドが完了するのを待つ
for thread in threads:
thread.join()
このコードでは、lock
オブジェクトを使用してthread_method
内のクリティカルセクションを保護しています。with lock:
ブロック内のコードは、他のスレッドが同じロックを取得するまで実行されません。これにより、共有リソースへの同時アクセスによるデータの不整合を防ぎます。
ロックを正しく使用することで、スレッドセーフなプログラムを実現できます。
Socket.ioサーバでのスレッド起動
Socket.io
サーバを利用する際、バックグラウンドで並列処理を行うためには、start_background_task()
メソッドを使用してスレッドを起動します。
import socketio
sio = socketio.AsyncServer(cors_allowed_origins='*', async_mode = 'aiohttp')
sio.start_background_task(background_task, arg1, arg2)
async def background_task(arg1, arg2):
# process