Python プログラミング

【Python】マルチスレッドの使い方【Thread】

2021年4月23日

Pythonには、マルチスレッドと呼ばれるテクニックがあります。
一般的にプログラム言語は上から下に順番に1行ずつ実行されるものです。
Pythonでは、それをスレッドとして複数同時に取り扱うことが可能です。
このテクニックをマルチスレッドと呼びます。
マルチスレッドを利用することで、全体の処理時間を短縮することができます。

今回は、そのマルチスレッドの使い方を解説します。

マルチスレッドとは?

通常、Pythonで実行している処理の流れは、上から順番に1行ずつ実行されます。
したがって、途中で何か重い処理があると、その行で処理が終了するまで、全体の処理の流れが止まってしまいます。

そこで、マルチスレッドが登場します。
1行ずつ実行される処理をスレッドとして、複数のスレッドを同時に実行することをマルチスレッドと呼びます。
これを活用することによって、重い処理はスレッドを分けて実行することで、全体の処理時間を短縮することができます。

Pythonでは、main関数から実行されるスレッドをマルチスレッドと呼びます。
mainスレッドから派生して作成・実行されたメソッドを単にスレッドと呼びます。

マルチスレッドは、全体の処理時間を短縮することができますが、デメリットもあります。
それは、処理の順番に整合性がなくなることです。
複数のスレッドで同じクラスや変数に対して処理を加える場合は、十分に注意する必要があります。

使い方

使い方はとても簡単です。
以下のソースコードを例として、解説します。

import threading
import time

def process():
    print('Process Start')
    time.sleep(3)
    print('Process End')

print('Main Start')

threadA = threading.Thread(target=process)
threadA.start()

time.sleep(1)

print('Main End')

1行目で、マルチスレッドに必要なモジュールをimportしてます。
threadingは、特にpip insallなどは不要で、標準で使用することができます。

2行目の、timeモジュールは、マルチスレッドとは特に関係しません。
6行目で、一定時間処理を止めるため、time.sleep()が使用したいので、importしました。

4~7行目はスレッドで実行する用の関数です。
time.sleep()を何らかの重たい処理と捉えてください。

11行目で、threadAと言うスレッドを定義しています。
threadAは、process()を実行するスレッドとなりました。
このように、スレッドの定義は、関数に対しておこないます。

12行目で、threadAを開始しました。
定義した通りに関数が実行されます。

さて、このソースコードの実行結果は以下の通りです。

Main Start
Process Start
Main End
Process End

11,12行目でスレッドを使ったので、process()の出力が後ろにきました。
また、実行時間もsleepは合計で4秒ありますが、3秒で終わりました。

11,12行目を、単にprocess()に置き換えた場合(つまり、マルチスレッド化しない場合)の実行結果は以下の通りです。
こちらの場合は、4秒かかりました。

Main Start
Process Start
Process End
Main End

追記:
上記の例では、threadAの終了を待たずにメインスレッドを終了させてしまっています。
実はこれは良くないことですので、下記補足のテクニックを使って、スレッドがmainスレッドよりも早く終わらないようにするか、デーモン化してください。

補足

join()を使ったスレッドの終了方法

上記の例では、メインのスレッドが先に終わってしまいました。
threadAとメインの終了を同時にしたい場合は、以下のようにjoinメソッドを使います。

import threading
import time

def process():
    print('Process Start')
    time.sleep(3)
    print('Process End')


print('Main Start')

threadA = threading.Thread(target=process)
threadA.start()

print('Main Process')
time.sleep(1)

threadA.join()

print('Main End')
Main Start
Main Process
Process Start
Process End
Main End

join()を使うことで、メインのスレッドは18行目で処理を停止して、threadAの終了を待ちます。

処理をどこかのタイミングで同期させたい時などに有効です。

デーモンを使ったスレッドの終了方法

上記の例では、メインスレッドがthreadAよりも早く終わってしまいました。
メインスレッド終了後も、threadAが生き残り、処理を続けることとなりました。

作ったスレッドをメインスレッドの終了とともに、終了させる方法があります。
それは、スレッドをデーモン化することです。

以下がスレッドのデーモン化の例です。

import threading
import time

def process():
    print('Process Start')
    time.sleep(3)
    print('Process End')


print('Main Start')

threadA = threading.Thread(target=process)
threadA.setDaemon(True)
threadA.start()

time.sleep(1)

print('Main End')
Main Start
Process Start
Main End

メインスレッドの終了を持って、threadAも終了したので、'Process End'は出力されませんでした。

非常に重たい処理があるときに、有効なテクニックです。

Python学習におすすめの教材

Pythonについて、しっかりと基礎から学びたい、実践的なスキルを身につけたいと考えている方向けに、おすすめの学習教材を紹介します。
これらの教材は、実際に僕がPythonの学習に使った教材になっています。

現役シリコンバレーエンジニアが教えるPython 3 入門 + 応用 +アメリカのシリコンバレー流コードスタイル

現役シリコンバレーエンジニアが教えるPython入門!応用では、データ解析、データーベース、ネットワーク、暗号化、並列化、テスト、インフラ自動化、キューイングシステム、非同期処理など盛り沢山の内容です!

ベネッセが運営する動画学習サイトUdemyで視聴することができる動画教材です。
(セールの時には¥1,500程度で買えます!)

Pythonは自由度が高くて雑に書いても動きますが、その分コードスタイルがおろそかになりがちです。
正しいコードスタイルを身に着けておかなければ、Pythonプログラマとして活躍することはあり得ません。
この教材は、グローバルスタンダードなコードスタイルを正しく学びながら、アルゴリズムやサーバー構築など幅広くPythonの活用方法を学習することができます。

Pythonの学習で間違えたくない方や、趣味レベルのスキルから一歩抜け出したい方におすすめです。

エキスパートPythonプログラミング改訂2版 Pythonプログラミングのベストプラクティスを伝授

本書は、Pythonを使って仕事をしている開発者が普段どのようなツールやテクニックを用いて仕事をしているのか、また開発者が実際に現場で用いているベストプラクティスについて解説した書籍です。本書を読むことで、先進的なPythonプログラマが日常的に使用している開発ノウハウを学ぶことができます。

こちらの書籍は、様々なユースケースに対するベストプラクティスを学習することができる書籍です。
Python2系と3系の違いについてもよく取り上げられますので、実質どちらのバージョンにも対応しているといえます。

Pythonをうまく使いこなせていない気がする方、初心者の殻を破りたい方におすすめです。

-Python, プログラミング
-,