Select Language

AI Technology Community

8.3、Python threadingモジュールの使い方

threadパッケージに比べて、threadingパッケージはより多くの機能を提供します。このパッケージの使い方は基本的に2ステップに分けられます:

  • 最初のステップは、threading.Threadのインスタンスオブジェクトを作成することです。このとき、このオブジェクトに対応するスレッドは「新規作成」状態になります。

  • 2番目のステップは、このオブジェクトを操作することです。例えば、start()を呼び出して、このスレッドを「就緒」状態に変換します。

スレッドインスタンスオブジェクトの作成

既存のthreading.Threadクラスに基づくインスタンスオブジェクトを作成することができます。主にエントリ関数と対応するパラメータを提供する必要があります。エントリ関数は前の関数を再利用します。コードは次の通りです:

書式設定してコピー
def thread_entry(id):
    cnt = 0
    while cnt < 10:
        print('Thread:(%d) Time:%s' % (id, time.ctime()))
        time.sleep(1)
        cnt = cnt + 1

次に、このインスタンスを作成します。コードは次の通りです:

>>> import threading
>>> thread1 = threading.Thread(target=thread_entry, name="thread 1", args=(1,))
>>> thread1.isAlive()          # スレッドが実行中かどうか
False
>>> thread1.name               # スレッド名
'thread 1'

スレッドインスタンスを作成する際に、エントリ関数、エントリ関数のパラメータ、スレッド名などを設定することができます。

Python 3では、daemonというフラグが追加されています。これは、このスレッドがバックグラウンドスレッドかどうかを示します。

Python 3では、デフォルトで作成されるスレッドはdaemonプロセスではありません。すべての非daemonスレッドが終了すると、プロセスが終了します。プロセスが終了すると、すべてのdaemonスレッドは強制的に終了します。これは、daemonスレッドは自動的にプロセスとともに終了し、非daemonスレッドはプロセスの終了を阻止することを意味します。つまり、プロセスはすべての非daemonスレッドが終了するのを待ちます。

次に、daemon属性の使い方をデモします。daemonスレッドを作成し、そのタスクが完了する前にメインスレッドを終了します。このとき、このdaemonスレッドが自動的に終了することがわかります。コードは次の通りです:

import sys, time
import threading                                        # スレッドライブラリを導入
def thread_entry():                                     # スレッドのエントリ関数
    left_round = 10                                     # 合計10ラウンドをループする
    print(' Child Thread: Start Running')
     while left_round > 0:
        print('Child Thread: Running, left round = %d' % left_round)
        time.sleep(0.5)
        left_round = left_round – 1
    print("Child Thread Quit")          # スレッドを終了する
def start_threads():                    # スレッドを起動する
    thread1 = threading.Thread(target=thread_entry, daemon=True)
    thread1.start()                     # スレッドを起動して、「就緒」状態にする
    time.sleep(0.8)
    print("Active Thread Number = %d" % threading.active_count())
    time.sleep(1.8)
    print("Main Thread Quit")           # メインスレッドを終了する
if __name__=='__main__':
    start_threads()

実行結果は次の通りです:

$ python3 demo2.py
Thread: Start Running
Child Thread: Running, left round = 10
Child Thread: Running, left round = 9
Active Thread Number = 2                 # 現在、2つのスレッドがあります
Child Thread: Running, left round = 8
Child Thread: Running, left round = 7
Child Thread: Running, left round = 6
Child Thread: Running, left round = 5
Main Thread Quit                         # メインスレッドが終了し、プロセスが終了します

メインスレッドが終了すると、プロセスも終了することがわかります。daemonパラメータをFalseに設定すると、新しく作成されたスレッドはdaemonスレッドではなくなります。この場合、メインスレッドが終了しても、すべての非daemonスレッドが終了するまで、プロセスは終了しません。

上の例のstart_threads()関数を次のように変更します。他のコードは一切変更しません:

def start_threads():            # 非daemonスレッドを作成する
    thread1 = threading.Thread(target=thread_entry, daemon=False)
    thread1.start()
    time.sleep(0.8)
    print("Active Thread Number = %d" % threading.active_count())
    time.sleep(1.8)
    print("Main Thread Quit")

このプログラムを再度実行すると、結果は次の通りです:

$ python3 demo3.py
Child Thread: Start Running
Child Thread: Running, left round = 10
Child Thread: Running, left round = 9
Active Thread Number = 2
Child Thread: Running, left round = 8
Child Thread: Running, left round = 7
Child Thread: Running, left round = 6
Child Thread: Running, left round = 5
Main Thread Quit                  # メインスレッドが終了しましたが、プロセスは終了していません
Child Thread: Running, left round = 4
Child Thread: Running, left round = 3
Child Thread: Running, left round = 2
Child Thread: Running, left round = 1
Child Thread Quit                 # すべての非daemonスレッドが終了し、プロセスが終了します


Python 2では、スレッドを作成する際にdaemon属性を指定することはできませんが、作成後に属性を変更することができます。方法は次の通りです:

Threadインスタンスオブジェクト.set setDaemon(False)

Python 2では、新しく作成された非メインスレッドはデフォルトですべてdaemonスレッドです。つまり、プロセスが終了すると強制的に終了します。次はPython 2の例です。この例では、スレッドを作成した後、それを非daemonスレッドに設定します。これにより、プロセスはこのスレッドが終了するまで待機し、強制的に終了することはありません。主な変更はstart_threads()部分で、変更後の内容は次の通りです:

def start_threads():
    thread1 = threading.Thread(target=thread_entry)
    thread1.setDaemon(False)                    # 非daemonスレッドに変更する
    thread1.start()
    time.sleep(0.8)
    print("Active Thread Number = %d" % threading.active_count())
    time.sleep(1.8)
    print("Main Thread Quit")

実行結果は次の通りです:

$ python demo4.py
Child Thread: Start Running
Child Thread: Running, left round = 10
Child Thread: Running, left round = 9
Active Thread Number = 2
Child Thread: Running, left round = 8
Child Thread: Running, left round = 7
Child Thread: Running, left round = 6
Child Thread: Running, left round = 5
Main Thread Quit                        # メインスレッドが終了しましたが、プロセスはまだ終了していません
Child Thread: Running, left round = 4   # 新しく作成されたスレッドはまだ実行中です
Child Thread: Running, left round = 3
Child Thread: Running, left round = 2
Child Thread: Running, left round = 1
Child Thread Quit                       # 新しく作成されたスレッドが終了し、プロセスが終了します

独自のスレッドクラスを派生する

上では、threading.Threadのインスタンスオブジェクトを作成することでスレッドを作成しました。実際には、独自のスレッドクラスを作成し、それを使用してインスタンスオブジェクトを作成することで、スレッドを作成することもできます。もち

post
  • 10

    item of content
プロセスはリソースを分配する単位であり、スレッドはオペレーティングシステムがスケジューリングできる最小の単位です。
通常、プロセスには少なくとも1つのスレッドが含まれ、複数のスレッドがある場合はその中にメインスレッドが含まれます。同じプロセス内のすべてのスレッドはシステムリソースを共有しますが、それぞれが独立したスタック、レジスタ環境、およびローカルストレージを持っています。
マルチスレッドの利点は、複数のタスクを同時に実行できることです。システムに複数の計算ユニットがある場合、複数のスレッドはそれぞれの計算ユニットで並行して動作することができ、これによりシステムの処理効率が大幅に向上します。
多くの場合、プロセスはスレッドよりも大きい単位であり、通常1つのプロセスは複数のスレッドを含むことができます。プロセスの隔離効果はスレッドよりも優れているため、マルチプロセスを使用するとマルチスレッドよりも安全です。ただし、マルチプロセスの欠点はマルチスレッドよりもスケジューリングが重く、効率が低いことです。