logo

Python でのマルチスレッド化

この記事では、Python プログラミング言語におけるマルチスレッドの基本について説明します。と同じように マルチプロセッシング , マルチスレッドはマルチタスクを実現する方法です。マルチスレッドにおける概念は、 スレッド 使用されている。まずは概念を理解しましょう コンピュータアーキテクチャの分野で。

Python のプロセスとは何ですか?

コンピューティングでは、 プロセス 実行されているコンピュータ プログラムのインスタンスです。どのプロセスにも 3 つの基本コンポーネントがあります。



  • 実行可能プログラム。
  • プログラムに必要な関連データ (変数、ワークスペース、バッファなど)
  • プログラムの実行コンテキスト(プロセスの状態)

Python スレッドの概要

実行をスケジュールできるプロセス内のエンティティです。また、OS(Operating System)上で実行できる処理の最小単位のことです。簡単に言うと、スレッドとは、他のコードから独立して実行できるプログラム内の一連の命令です。わかりやすくするために、スレッドは単なるプロセスのサブセットであると想定できます。スレッドにはこれらすべての情報が含まれています スレッド制御ブロック (TCB) :

  • スレッド識別子: 新しいスレッドごとに一意の ID (TID) が割り当てられます。
  • スタックポインタ: プロセス内のスレッドのスタックを指します。スタックには、スレッドのスコープ内のローカル変数が含まれます。
  • プログラムカウンター: スレッドによって現在実行されている命令のアドレスを格納するレジスタ。
  • スレッドの状態: 実行中、準備完了、待機中、開始中、完了済みのいずれかです。
  • スレッドのレジスタセット: 計算のためにスレッドに割り当てられたレジスタ。
  • 親プロセス ポインタ: スレッドが存在するプロセスのプロセス制御ブロック (PCB) へのポインター。

プロセスとそのスレッドの関係を理解するには、以下の図を考慮してください。

マルチスレッド-Python-11

プロセスとそのスレッドの関係



以下の場合、1 つのプロセス内に複数のスレッドが存在できます。

  • 各スレッドには独自のものが含まれています レジスタセット そして ローカル変数 (スタックに格納)
  • プロセス共有のすべてのスレッド グローバル変数 (ヒープに格納) そしてその プログラムコード

メモリ内に複数のスレッドがどのように存在するかを理解するには、以下の図を考慮してください。

マルチスレッド-Python-21

メモリ内に複数のスレッドが存在する



Python のスレッド化の概要

マルチスレッド化 プロセッサが複数のスレッドを同時に実行できる能力として定義されます。シンプルなシングルコア CPU では、スレッド間の頻繁な切り替えを使用してこれを実現します。これを コンテキストスイッチング 。コンテキスト切り替えでは、(I/O または手動設定による) 割り込みが発生するたびに、スレッドの状態が保存され、別のスレッドの状態がロードされます。コンテキストの切り替えが頻繁に行われるため、すべてのスレッドが並行して実行されているように見えます (これは、 マルチタスク )。

プロセスに 2 つのアクティブなスレッドが含まれている以下の図を考えてみましょう。

マルチスレッド-Python-31

マルチスレッド化

Python でのマルチスレッド化

パイソン ねじ切り モジュールは、プログラム内で複数のスレッドを生成するための非常にシンプルで直感的な API を提供します。マルチスレッド コードを段階的に理解してみましょう。

ステップ1: インポートモジュール

まず、スレッドモジュールをインポートします。

import threading>

ステップ2: スレッドを作成する

新しいスレッドを作成するには、 クラス。 「target」と「args」をパラメータとして受け取ります。の 目標 はスレッドによって実行される関数ですが、 引数は ターゲット関数に渡される引数。

t1 = threading.Thread(target, args) t2 = threading.Thread(target, args)>

ステップ 3: スレッドを開始する

スレッドを開始するには、 始める() Thread クラスのメソッド。

t1.start() t2.start()>

ステップ 4: スレッドの実行を終了する

スレッドが開始されると、現在のプログラム (メイン スレッドのように考えることができます) も実行を続けます。スレッドが完了するまで現在のプログラムの実行を停止するには、 参加する() 方法。

t1.join() t2.join()>

その結果、現在のプログラムはまず、次の処理の完了を待ちます。 t1 その後 t2 。それらが終了すると、現在のプログラムの残りのステートメントが実行されます。

例:

スレッドモジュールを使用した簡単な例を考えてみましょう。

このコードは、Python のスレッド モジュールを使用して数値の 2 乗と 3 乗を同時に計算する方法を示しています。 2つのスレッド、 t1> そして t2> 、これらの計算を実行するために作成されます。これらは開始され、プログラムが「Done!」を出力する前に、その結​​果が並行して出力されます。両方のスレッドが終了したとき。スレッド化は、計算負荷の高いタスクを処理するときに並列処理を実現し、プログラムのパフォーマンスを向上させるために使用されます。

Python3




import> threading> def> print_cube(num):> >print>(>'Cube: {}'> .>format>(num>*> num>*> num))> def> print_square(num):> >print>(>'Square: {}'> .>format>(num>*> num))> if> __name__>=>=>'__main__'>:> >t1>=> threading.Thread(target>=>print_square, args>=>(>10>,))> >t2>=> threading.Thread(target>=>print_cube, args>=>(>10>,))> >t1.start()> >t2.start()> >t1.join()> >t2.join()> >print>(>'Done!'>)>

>

>

出力:

Square: 100 Cube: 1000 Done!>

上記のプログラムがどのように動作するかをよりよく理解するために、以下の図を検討してください。

マルチスレッド-Python-4

マルチスレッド化

例:

この例では、 os.getpid() 現在のプロセスの ID を取得する関数。を使用しております threading.main_thread() メインスレッドオブジェクトを取得する関数。通常の状態では、メインスレッドは Python インタープリターが開始されたスレッドです。 名前 スレッド オブジェクトの属性は、スレッドの名前を取得するために使用されます。次に、 threading.current_thread() 現在のスレッドオブジェクトを取得する関数。

各タスクのスレッド名と対応するプロセスを出力する、以下の Python プログラムについて考えてみましょう。

このコードは、Python のスレッド モジュールを使用して 2 つのタスクを同時に実行する方法を示しています。メイン プログラムは 2 つのスレッドを開始します。 t1> そして t2> 、それぞれが特定のタスクの実行を担当します。スレッドは並行して実行され、コードはプロセス ID とスレッド名に関する情報を提供します。のos>モジュールはプロセス ID にアクセスするために使用され、 ' threading'> モジュールは、スレッドとその実行を管理するために使用されます。

Python3




import> threading> import> os> def> task1():> >print>(>'Task 1 assigned to thread: {}'>.>format>(threading.current_thread().name))> >print>(>'ID of process running task 1: {}'>.>format>(os.getpid()))> def> task2():> >print>(>'Task 2 assigned to thread: {}'>.>format>(threading.current_thread().name))> >print>(>'ID of process running task 2: {}'>.>format>(os.getpid()))> if> __name__>=>=> '__main__'>:> >print>(>'ID of process running main program: {}'>.>format>(os.getpid()))> >print>(>'Main thread name: {}'>.>format>(threading.current_thread().name))> >t1>=> threading.Thread(target>=>task1, name>=>'t1'>)> >t2>=> threading.Thread(target>=>task2, name>=>'t2'>)> >t1.start()> >t2.start()> >t1.join()> >t2.join()>

>

>

出力:

ID of process running main program: 1141 Main thread name: MainThread Task 1 assigned to thread: t1 ID of process running task 1: 1141 Task 2 assigned to thread: t2 ID of process running task 2: 1141>

以下の図は、上記の概念を明確にしています。

マルチスレッド-Python-5

マルチスレッド化

以上、Python のマルチスレッドについての簡単な紹介でした。このシリーズの次の記事では、 複数のスレッド間の同期 Python でのマルチスレッド |セット 2 (同期)

Python スレッドプール

スレッド プールは、事前に作成されたスレッドのコレクションであり、複数のタスクを実行するために再利用できます。 Python の concurrent.futures モジュールは、スレッド プールの作成と管理を簡単にする ThreadPoolExecutor クラスを提供します。

この例では、スレッドで実行される関数ワーカーを定義します。最大 2 つのワーカー スレッドを持つ ThreadPoolExecutor を作成します。次に、submit メソッドを使用して 2 つのタスクをプールに送信します。プールは、ワーカー スレッドでのタスクの実行を管理します。 shutdown メソッドを使用して、メインスレッドが続行する前にすべてのタスクが完了するのを待ちます。

マルチスレッドは、プログラムの効率と応答性を高めるのに役立ちます。ただし、スレッドを操作するときは、競合状態やデッドロックなどの問題を避けるために注意することが重要です。

このコードは、で作成されたスレッド プールを使用します。 concurrent.futures.ThreadPoolExecutor> 2 つのワーカー タスクを同時に実行します。メインスレッドはワーカースレッドの使用が完了するまで待機します。 pool.shutdown(wait=True)> 。これにより、マルチスレッド環境でのタスクの効率的な並列処理が可能になります。

Python3


文字列と比較する



import> concurrent.futures> def> worker():> >print>(>'Worker thread running'>)> pool>=> concurrent.futures.ThreadPoolExecutor(max_workers>=>2>)> pool.submit(worker)> pool.submit(worker)> pool.shutdown(wait>=>True>)> print>(>'Main thread continuing to run'>)>

>

>

出力

Worker thread running Worker thread running Main thread continuing to run>