2024.05.01
【Python】threadingモジュールの基本と並行処理の注意点を解説!
Pythonの threadingモジュールは、スレッドの生成や起動・同期など高いレベルのスレッドインターフェースを提供します。スレッドを使うことにより、プログラムの中で異なるタスクを実行できるため、全体的な効率アップに貢献します。
Pythonでは、 threadingモジュールを使うと手軽にスレッドを扱えることからも、基本概念をはじめマルチスレッドプログラミングへの理解を深めることが重要です。Pythonでのプログラミングに興味がある方や、マルチスレッド処理に興味がある方は、ぜひ最後までご覧ください。
この記事でわかること
- Pythonスレッドの概要
- threadingモジュールを用いた処理方法
- マルチスレッドプログラミングでの注意点
目次
【Python】スレッドとは?
Pythonでは、 threading(スレッディング)モジュールの利用で手軽にスレッドを扱えるほか、高度なスレッドインターフェースを提供します。主に、マルチスレッドプログラミングをする際に使用します。
スレッドとは、プログラムの中で並行してタスクを実行する手段のことです。同時に実行できるタスクの最小の処理単位でもあり、プログラムの中でいくつものスレッドを作成して、一つひとつを独立させて動かすこともできます。
はじめに、2つのスレッドを同時に動かすときのサンプルコードを見ていきましょう。
import threading import time def print_numbers(): for i in range(10): time.sleep(1) print(i) def print_letters(): for letter in ‘abcdefghij’: time.sleep(1.5) print(letter) thread1 = threading.Thread(target=print_numbers) thread2 = threading.Thread(target=print_letters) thread1.start() thread2.start() |
このケースでは、うえから3行目のprint_numbers関数と、うえから7行目のprint_letters関数をそれぞれ別のスレッドで記載し実行します。
threadingモジュールを用いた並行処理
Pythonのthreadingモジュールを用いた場合、いくつものスレッドを並行処理できるようになります。スレッドの生成はもちろん同期化などができるほか、それぞれのスレッドを切り替えて、並行して処理を実行できる点が魅力です。
以下のコマンドを使い、Pythonの標準モジュールであるthreadingライブラリを呼び出して、実際に操作しながら進めてみてください。
import threading |
また、基礎的なThreadオブジェクトは以下のとおりです。
- start():スレッドを開始する
- run():スレッドの処理をマニュアルで実行する
- join():スレッドの処理が終わるまで待機する
スレッドの作成方法とカスタマイズ
スレッドを増やすときは、threading.Thread()クラスをインスタンス化します。target引数にはスレッドで実行する関数を、args引数にはその関数の引数をタプルとして指定します。
たとえば、次のようなサンプルでは、Threadクラスを使ってprint_numbersとprint_lettersの2つの関数を実行可能です。
import threading import time def print_numbers(): # 数字を出力するスレッド for i in range(10): print(i) def print_letters(letter): # 文字を出力するスレッド for _ in range(10): print(letter) thread1 = threading.Thread(target=print_numbers) thread2 = threading.Thread(target=print_letters, args=(‘A’,)) thread1.start() thread2.start() |
thread2では、引数として受け取った文字Aを表示するために、print_letters関数を記述し実行しています。args引数は、タプル形式で関数の引数を指定します。引数がひとつでも、カンマ「,」をつけてタプル形式にすることがポイントです。
Threadクラスのサブクラス化
Threadクラスはサブクラス化も可能です。そのときは、threading.Thread()クラスを継承したクラスを定義してから、runメソッドをオーバーライドしてカスタマイズします。
class MyThread(threading.Thread): def run(self): print(“Custom thread starting.”) time.sleep(3) print(“Custom thread finishing.”) thread = MyThread() thread.start() |
また、__init__()とrun()メソッド以外では、オーバーライドはタブーなため注意が必要です。
スレッド名の設定
スレッド名は、デフォルトでは「Thread-数字」と名付けられています。スレッドの識別のために利用されますが、複数のスレッドに同じ名前を設定することもできます。
threading.Thread()クラスのコンストラクタにname引数を指定することで、スレッド名を設定できます。
import threading class MyThread(threading.Thread): def run(self): pass subthread1 = MyThread(name=”スレッド1″) print(subthread1.name) # スレッド1 subthread2 = threading.Thread(name=”スレッド2″) print(subthread2.name) # スレッド2 |
また、スレッド名を変更する際は、以下のようにnameプロパティへ直接代入します。
import threading class MyThread(threading.Thread): def run(self): pass subthread1 = MyThread(name=”スレッド1″) print(subthread1.name) # スレッド1 subthread1.name = “T1” print(subthread1.name) # T1 subthread2 = threading.Thread(name=”スレッド2″) print(subthread2.name) # スレッド2 subthread1.name = “T2” print(subthread1.name) # T2 |
マルチスレッドプログラミングの注意点と解決策
threadingモジュールを用いたマルチスレッドプログラミングは、柔軟なカスタマイズ性があり、開発者にとっても習得したいものです。しかし、注意しなければならない代表的なウィークポイントが2つあります。
ひとつは、Pythonの仕様であるグローバルインタープリタロック(GIL)です。GILは一度にひとつのスレッド実行の制限があるため、場合によって思い描くパフォーマンスを発揮できない可能性が出てきます。
GILの制限には、multiprocessingモジュールの使用が適しており、各プロセスに独立したPythonインタープリタを割り当てて、GILの制限を受けずに済みます。
もうひとつは、ロックはリソースへの同時アクセスを防止するために不可欠ですが、適切に使用されないとデッドロックを引き起こす可能性があります。
そのため、使用するときは必要な範囲のみ、使用後はすぐ開放するといった対処を意識しなければなりません。
Pythonの標準モジュールのなかでも、パッケージ管理システムである「pip」は便利なモジュールとして知られていますが、Pythonのバージョンによっては別途インストールが必要です。こちらの記事では、pipのインストール方法について解説します。
まとめ
今回は、Pythonのthreadingモジュールを使い、スレッドを並行処理する2つのやり方を中心に、カスタムスレッドの作り方、マルチスレッドプログラミングをするときの2つの注意点を紹介しました。
Pythonでマルチスレッドプログラミングをすると、タスクの並列で効率的に実現できることが魅力です。しかし、その一方で注意したいポイントもあり、理解を深めて適した使い方をしなければなりません。
Pythonでのプログラミングに興味がある方にとって、 Pythonでマルチスレッドプログラミングを習得することは、自身のスキルアップにもつながります。作成したアプリのパフォーマンス向上にも貢献するため、この機会にマスターしておきましょう。
投稿者
-
システム開発、Webサイト制作、ECサイトの構築・運用、デジタルトランスフォーメーション(DX)など、デジタルビジネスに関わる多岐の領域において、最新のトレンド情報や実践的なノウハウを発信してまいります。
新着情報
同じカテゴリの記事
新着記事
人気の記事