Python スレッドの優先度

Abid Ullah 2023年6月21日
  1. Python でのスレッド化
  2. Python スレッドのスケジューリング優先度の制御
Python スレッドの優先度

この記事の目的は、Python でスケジューリング スレッドを使用してそれを優先する方法を説明することです。 ここでは、Python で優先スレッドをスケジュールし、それを良いサンプル プログラムで使用する方法について説明します。

Python スレッドを使用すると、プログラムのさまざまな部分を同時に実行できるため、プログラムの設計が容易になります。 Python の知識がある場合は、スレッドを使用して Python プログラムを高速化する方法を紹介します。

Python でのスレッド化

スレッド化は、複数の命令を同時に実行する機能です。 この記事で説明するように、スケジューリングを調整することでスレッドに優先順位を付けることができます。

グローバル インタープリター ロック (GIL) を使用して Python スレッドを実装します。つまり、スレッドの優先度を制御することはできません。 優先度を使用してスレッドを制御するには、暗黙的な優先度システムを作成する必要があります。

スレッド化では、2つ (またはそれ以上) のプロセッサがプログラム上で同時に実行され、それぞれが独立したタスクを実行していると想像できます。

それは真実に非常に近いです。 各スレッドは、異なるプロセッサであっても、1つのプロセッサで同時に実行されます。

複数のタスクを同時に実行するには、非標準の Python 実装が必要になるか、別の言語でコードを作成する必要があるか、追加のオーバーヘッドでマルチプロセッシングを使用する必要がある場合があります。

Python の C 実装は常にスレッド化をサポートしているわけではないため、スレッド化によってすべてのタスクが高速化されるとは限りません。 GIL インタラクションは、同時に実行できる Python スレッドの数を制限します。

通常、スレッド化は、外部イベントの待機に多くの時間を費やすタスクに適しています。 負荷の高い CPU 計算を必要とするが、外部イベントの待機にほとんど時間を費やさない問題は、他の問題ほど速く実行されない可能性があります。

Python スレッドのスケジューリング優先度の制御

正しいバージョンの Python で作業していることを確認することが重要です。 この記事専用にバージョン 3.10.4 を使用しています。

ターミナルで以下のコマンドを実行すると、現在インストールされている python のバージョンを確認できます。

python --version

便利なライブラリのインポート

次のステップは、スレッドとは何かを理解した後、スケジューリング優先度を使用してスレッドを作成する方法を学習することです。 この記事で紹介するプリミティブのほとんどは、Python 標準ライブラリによってスレッド化によって提供されます。

このモジュールでは、Thread はスレッドと対話するための優れたインターフェイスを提供し、スレッドを適切にカプセル化します。

次に、プログラムの次のフェーズに進みます。ここでは、Python スレッドの優先度をスケジュールするために必要なライブラリをインポートします。

コード例:

import time
from threading import Thread
from time import sleep

Thread インスタンスを使用し、.start() に指示することで、別のスレッドを開始することができます。

コード例:

import logging
import threading
import time


def the_thread_function(name):
    logging.info("The thread %s: Beginning now", name)
    time.sleep(2)
    logging.info("The Thread %s: Ends", name)


if __name__ == "__main__":
    format = "%(asctime)s: %(message)s"
    logging.basicConfig(format=format, level=logging.INFO, datefmt="%H:%M:%S")
    logging.info("Main    : Now before creating a thread")
    x = threading.Thread(target=the_thread_function, args=(1,))
    logging.info("Main    : Earlier than running threading")
    x.start()
    logging.info("Main    : Now wait for the thread to End")
    # x.join()
    logging.info("Main    : All Finish")

出力:

17:06:51: Main    : Now before creating a thread
17:06:51: Main    : Earlier than running threading
17:06:51: The thread 1: Beginning now
17:06:51: Main    : Now wait for the thread to End
17:06:51: Main    : All Finish
17:06:53: The Thread 1: Ends

ログ ステートメントでは、メイン セクションがスレッドの作成と開始を行っていることがわかります。スレッドに引数リストと呼び出したい関数を渡すことで、スレッドを作成します。

この場合、Threadthread_function() を実行し、引数として 1 を渡すように指示されます。

Python での多数のスレッドのスケジュールの優先度の操作

現在、サンプル コードは 2つのスレッド、メイン スレッドとスレッド Thread オブジェクトで開始したスレッドでのみ動作します。 多くのスレッドを開始して、興味深いことに取り組んでもらいたいと思うことがよくあります。

次に、それを行うためのより簡単な方法を見てみましょう。 より難しい方法を見てみましょう。

コード例:

import logging
import threading
import time


def thread_function(name):
    logging.info("Thread %s: Beginning", name)
    time.sleep(2)
    logging.info("Thread %s: Ending", name)


if __name__ == "__main__":
    format = "%(asctime)s: %(message)s"
    logging.basicConfig(format=format, level=logging.INFO, datefmt="%H:%M:%S")
    threads = list()
    for index in range(3):
        logging.info("Main    : create and start thread %d.", index)
        x = threading.Thread(target=thread_function, args=(index,))
        threads.append(x)
        x.start()
    for index, thread in enumerate(threads):
        logging.info("Main    : Before joining thread %d.", index)
        thread.join()
        logging.info("Main    : thread %d end", index)

出力:

17:09:01: Main    : create and start thread 2.
17:09:01: Thread 2: Beginning
17:09:01: Main    : Before joining thread 0.
17:09:03: Thread 0: Ending
17:09:03: Main    : thread 0 end
17:09:03: Main    : Before joining thread 1.
17:09:03: Thread 1: Ending
17:09:03: Main    : thread 1 end
17:09:03: Main    : Before joining thread 2.
17:09:03: Thread 2: Ending
17:09:03: Main    : thread 2 end

Thread オブジェクトを作成し、.start() を呼び出して、先ほどスレッドを開始したのと同じ方法でスレッドを開始します。 Thread オブジェクトのリストを保持することで、プログラムは後で .join() を使用してそれらを待つことができます。

出力を注意深く見ると、3つのスレッドすべてが予想どおりの順序で開始されていることがわかります。 ただし、この場合は逆の順序で終了します。

複数の実行により、異なる注文が生成および出力されます。 Thread x: Nearing End メッセージを探して、各 Thread がいつ終了するかを通知します。

オペレーティング システムはスレッドが実行される順序を決定しますが、これを予測するのは非常に困難です。 アルゴリズムでのスレッド化の使用は、実行ごとに異なる可能性があります (おそらくそうなるでしょう)。そのため、アルゴリズムを開発するときはそのことを念頭に置いてください。

Python がスレッドを調整し、それらを相互に調整するためのいくつかのプリミティブを提供していることは素晴らしいことです。 最初に、スレッドのグループの管理を簡単にする方法を見ていきます。

Worker クラスの作成

この worker クラスを使用すると、各スレッドに実行時間を設定できるようにスクリプトを設定できます。 結果の形のように、1つのスレッドの優先度が高い場合、他のスレッドをより長くスリープさせます。

Worker クラスは、マルチスレッドに役立つ単純な MFC クラスです。 作業を実行するためにスレッドを必要とするオブジェクトは、Worker クラスから継承されます。

Do-Work 機能を使用して長いプロセスを実行し、オブジェクトで Start/Stop/Pause を使用して実行します。

コード例:

import time
from threading import Thread
from time import sleep


class Worker(Thread):
    def __init__(self, pri):
        Thread.__init__(self)
        self.pri = pri

    def run(self):
        for i in range(20):
            sleep(1.0 * self.pri)
            print(" -thread with priority:", self.pri)


w1 = Worker(1.0)
w2 = Worker(0.75)
w3 = Worker(0.5)
start = time.time()
w1.start()
w2.start()
w3.start()
end = time.time()

このステップの一環として、ワーカーを初期化しました。 その後、優先度の異なる複数のスレッドを作成しました。

ワーカー スレッドは次のように実行されます。

Output exceeds the size limit. Open the full output data in a text editor
 -thread with priority: 0.5
 -thread with priority: 0.75
 -thread with priority: 1.0
 -thread with priority: 0.5
 -thread with priority: 0.75
 -thread with priority: 0.5
 -thread with priority: 1.0
 -thread with priority: 0.5
 -thread with priority: 0.75
 -thread with priority: 0.5
 -thread with priority: 1.0
 -thread with priority: 0.75

平均して、スレッド実行の出力トレースを見ると、優先度 0.5 および 0.75 のスレッドは、実行後に優先度 1.0 のスレッドよりも頻繁に呼び出されることがわかります。

次の例は、単純な Python スクリプトが優先度に基づいて Python スレッドをスケジュールする方法を示しています。

Python スレッド化の例と、多数のスレッドを使用してスレッド化されたプログラムを構築する方法、スケジューリングの優先順位、およびそれらが解決する問題を見てきました。 start()join()time()worker クラス、およびその他の多くのメソッドの使用も実証されています。

この記事が、Python でスレッドを使用する方法を理解するのに役立つことを願っています。

著者: Abid Ullah
Abid Ullah avatar Abid Ullah avatar

My name is Abid Ullah, and I am a software engineer. I love writing articles on programming, and my favorite topics are Python, PHP, JavaScript, and Linux. I tend to provide solutions to people in programming problems through my articles. I believe that I can bring a lot to you with my skills, experience, and qualification in technical writing.

LinkedIn

関連記事 - Python Thread