ホームページ >バックエンド開発 >Python チュートリアル >Pythonマルチプロセスと並列プログラミングのガイド

Pythonマルチプロセスと並列プログラミングのガイド

Lisa Kudrow
Lisa Kudrowオリジナル
2025-02-19 08:26:11447ブラウズ

Pythonマルチプロセスと並列プログラミングのガイド

計算をスピードアップすることは、誰もが達成したい目標です。現在の実行時間よりも10倍速く実行できるスクリプトがある場合はどうなりますか?この記事では、Python MultiprocessingとMultiProcessingと呼ばれるライブラリを見ていきます。並列プログラミングを使用して、マルチプロセッシングが何であるか、その利点、およびPythonプログラムの実行時間を改善する方法について説明します。

わかりました、行こう!

キーテイクアウト

    並列コンピューティングは、CPUの複数のコアを同時に使用することにより、計算をスピードアップする方法です。これは、複数のプロセスを作成できるモジュールであるMultiProcessingを介してPythonで実現できます。それぞれが別のコアで実行されます。
  • Pythonのマルチプロセッシングモジュールは、高集約的なタスクのCPUの使用、スレッドと比較した子どものプロセスのより多くの制御、並列プログラミングに適したタスクの簡単な実装などの利点を提供します。
  • Pythonマルチプロセッシングは、シリアルコンピューティングよりも常に効率的ではありません。 CPU集約型タスクが低い場合、プロセス間で計算を分割することで導入されたオーバーヘッドのため、シリアル計算はより速くなります。
  • Pythonのマルチプロセッシングモジュールは、同時に実行する必要がある各タスクの新しいプロセスを作成します。各プロセスには、独自のPythonインタープリターとメモリスペースがあり、他のプロセスとは独立して実行できます。
  • Pythonでのマルチプロセシングは、プログラムの速度と効率を大幅に改善できますが、コードの複雑さも向上します。すべてのタスクが並列化に適しているわけではなく、場合によっては、複数のプロセスの作成と管理のオーバーヘッドが潜在的なパフォーマンスの向上を上回る可能性があります。
  • 並列性の紹介
  • Pythonコードに飛び込む前に、コンピューターサイエンスの重要な概念である並列コンピューティングについて話さなければなりません。
  • 通常、Pythonスクリプトを実行すると、ある時点でコードがプロセスになり、プロセスがCPUの単一のコアで実行されます。しかし、最新のコンピューターには複数のコアがあるので、計算にもっと多くのコアを使用できるとしたらどうでしょうか?計算はより速くなることがわかります
  • 今のところこれを一般原則として見てみましょうが、後でこの記事では、これは普遍的に真実ではないことがわかります。
あまりにも多くの詳細に入ることなく、並列性の背後にあるアイデアは、CPUの複数のコアを使用できるようにコードを書くことです。

物事を簡単にするために、例を見てみましょう。

並列およびシリアルコンピューティング

あなたが解決すべき大きな問題を抱えていると想像してください、そしてあなたは一人です。 8つの異なる数値の平方根を計算する必要があります。職業はなんですか?まあ、あなたには多くの選択肢がありません。最初の番号から始めて、結果を計算します。次に、他の人と一緒に行きます。

あなたがあなたを助けてくれる数学が得意な3人の友達がいるとしたら?それらのそれぞれは2つの数値の平方根を計算し、仕事の負荷は友達の間で均等に分配されるため、仕事は簡単になります。これは、問題がより速く解決されることを意味します

わかりました、すべて明確ですか?これらの例では、各友人はCPUのコアを表しています。最初の例では、タスク全体があなたによって連続的に解決されます。これはシリアルコンピューティングと呼ばれます。 2番目の例では、合計4つのコアを使用しているため、並列コンピューティングを使用しています。並列コンピューティングには、プロセッサ内の複数のコア間で分割される並列プロセスまたはプロセスの使用が含まれます。

並列プログラミングのモデルPythonマルチプロセスと並列プログラミングのガイド

並列プログラミングとは何かを確立しましたが、どのように使用しますか?さて、並行コンピューティングには、プロセッサの複数のコア間で複数のタスクの実行が含まれることを意味します。つまり、これらのタスクは同時に実行されることを意味します。並列化に近づく前に考慮すべきいくつかの質問があります。たとえば、計算をスピードアップできる他の最適化はありますか?

今のところ、並列化があなたにとって最良の解決策であると当然のことと考えてみましょう。並列コンピューティングには主に3つのモデルがあります:

完全に平行。タスクは独立して実行でき、互いに通信する必要はありません。

共有メモリの並列性。プロセス(またはスレッド)が通信する必要があるため、グローバルアドレス空間を共有します。
    メッセージの合格。必要に応じてプロセスがメッセージを共有する必要があります。
  • この記事では、最初のモデルを説明します。これも最も簡単です。
  • Pythonマルチプロセッシング:Pythonのプロセスベースの並列性
  • Pythonで並列性を実現する1つの方法は、マルチプロセッシングモジュールを使用することです。マルチプロセッシングモジュールを使用すると、複数のプロセスを作成できます。それぞれが独自のPythonインタープリターを使用します。このため、Pythonマルチプロセッシングはプロセスベースの並列性を達成します
  • Pythonが組み込まれているスレッドのような他のライブラリについて聞いたことがあるかもしれませんが、それらの間には重要な違いがあります。マルチプロセッシングモジュールは新しいプロセスを作成し、スレッドは新しいスレッドを作成します。
次のセクションでは、マルチプロセッシングを使用することの利点について説明します。 マルチプロセッシングを使用することの利点

マルチプロセッシングのいくつかの利点があります:

  • 高いCPU集約型タスクを扱うときのCPUのより良い使用
  • スレッドと比較して子供をより多く制御します
  • 簡単にコードできます

最初の利点はパフォーマンスに関連しています。 Multiprocessingは新しいプロセスを作成するため、タスクを他のコアに分割することにより、CPUの計算能力をよりよく使用できます。ほとんどのプロセッサは最近のマルチコアプロセッサであり、コードを最適化する場合は、計算を並行して解決することで時間を節約できます。 2番目の利点は、マルチスレッドであるマルチプロセスの代替手段を調べます。ただし、スレッドはプロセスではなく、これに結果が生じます。スレッドを作成する場合、通常のプロセスで行うように、スレッドを殺したり、中断することも危険です。マルチプロセッシングとマルチスレッドの比較はこの記事の範囲内ではないため、さらに読むことをお勧めします。

マルチプロセッシングの3番目の利点は、処理しようとしているタスクが並列プログラミングに適していることを考えると、実装が非常に簡単であることです。

Python Multiprocessing

を開始します

ついにPythonコードを書く準備ができています!

非常に基本的な例から始めます。これを使用して、Pythonマルチプロセッシングのコア側面を説明します。この例では、2つのプロセスがあります

親プロセス。複数の子供を持つことができる親のプロセスは1つだけです。

子プロセス。これは親によって生まれました。各子供には新しい子供もいることもあります。

  • 子どものプロセスを使用して、特定の関数を実行します。このようにして、親はその実行を続けることができます。
  • 単純なPythonマルチプロセッシングの例
  • この例で使用するコードは次のとおりです
このスニペットでは、bubble_sort(array)という関数を定義しました。この関数は、バブルソートソートアルゴリズムの非常に素朴な実装です。それが何であるかわからないとしても、心配しないでください。それはそれほど重要ではないからです。知っておくべき重要なことは、それがいくつかの作業を行う関数であるということです。

プロセスクラス

マルチプロセッシングから、クラスプロセスをインポートします。このクラスは、別のプロセスで実行されるアクティビティを表します。確かに、あなたは私たちがいくつかの議論に合格したことを見ることができます:

ターゲット= bubble_sort、つまり、新しいプロセスがbubble_sort関数を実行することを意味します
<span>from multiprocessing import Process
</span>
<span>def bubble_sort(array):
</span>    check <span>= True
</span>    <span>while check == True:
</span>      check <span>= False
</span>      <span>for i in range(0, len(array)-1):
</span>        <span>if array[i] > array[i+1]:
</span>          check <span>= True
</span>          temp <span>= array[i]
</span>          array<span>[i] = array[i+1]
</span>          array<span>[i+1] = temp
</span>    <span>print("Array sorted: ", array)
</span>
<span>if __name__ == '__main__':
</span>    p <span>= Process(target=bubble_sort, args=([1,9,4,5,2,6,8,4],))
</span>    p<span>.start()
</span>    p<span>.join()
</span>

args =([1,9,4,52,6,8,4]、)、これはターゲット関数への引数として渡される配列

プロセスクラスのインスタンスを作成したら、プロセスを開始するだけです。これは、p.start()を書くことによって行われます。この時点で、プロセスが開始されます

出口を終える前に、子どものプロセスが計算を終了するのを待つ必要があります。 Join()メソッドは、プロセスが終了するのを待ちますこの例では、1つの子プロセスのみを作成しました。ご想像のとおり、プロセスクラスでより多くのインスタンスを作成することで、より多くの子プロセスを作成できます。

プールクラス

より多くのCPU集約型タスクを処理するために複数のプロセスを作成する必要がある場合はどうなりますか?私たちは常に終了を明示的に開始し、待つ必要がありますか?ここでの解決策は、プールクラスを使用することです

プールクラスを使用すると、ワーカープロセスのプールを作成できます。次の例では、どのように使用できるかについて説明します。これは私たちの新しい例です:

このコードスニペットでは、単に整数を採取して平方根を返すキューブ(x)関数があります。簡単ですよね?

次に、属性を指定せずにプールクラスのインスタンスを作成します。プールクラスは、デフォルトでCPUコアごとに1つのプロセスを作成します。次に、いくつかの引数でMAPメソッドを実行します。
<span>from multiprocessing import Process
</span>
<span>def bubble_sort(array):
</span>    check <span>= True
</span>    <span>while check == True:
</span>      check <span>= False
</span>      <span>for i in range(0, len(array)-1):
</span>        <span>if array[i] > array[i+1]:
</span>          check <span>= True
</span>          temp <span>= array[i]
</span>          array<span>[i] = array[i+1]
</span>          array<span>[i+1] = temp
</span>    <span>print("Array sorted: ", array)
</span>
<span>if __name__ == '__main__':
</span>    p <span>= Process(target=bubble_sort, args=([1,9,4,5,2,6,8,4],))
</span>    p<span>.start()
</span>    p<span>.join()
</span>
マップメソッドは、私たちが提供する反復可能なすべての要素にキューブ関数を適用します。この場合、10からNのすべての数字のリストです。

これの大きな利点は、リストの計算が並行して行われていることです!

Python Multiprocessingを最大限に活用

複数のプロセスを作成し、並列計算を行うことは、必ずしもシリアルコンピューティングよりも効率的ではありません。 CPU集約型タスクが低い場合、シリアル計算は並列計算よりも高速です。このため、マルチプロセッシングをいつ使用するかを理解することが重要です。これは、実行しているタスクに依存します。

これを納得させるには、簡単な例を見てみましょう:

このスニペットは、前の例に基づいています。同じ問題を解決しています。これは、n数の平方根を計算していますが、2つの方法で計算されています。最初のものは、Pythonマルチプロセッシングの使用を含みますが、2番目のものはPythonマルチプロセッシングです。時間のパフォーマンスを測定するために、時間ライブラリのperf_counter()メソッドを使用しています。

私のラップトップで、この結果が得られます:

ご覧のとおり、1秒以上の違いがあります。したがって、この場合、マルチプロセッシングの方が優れています

Nの値のようにコードの何かを変更しましょう。n = 10000に下げて、何が起こるかを見てみましょう。
<span>from multiprocessing import Pool
</span><span>import time
</span><span>import math
</span>
N <span>= 5000000
</span>
<span>def cube(x):
</span>    <span>return math.sqrt(x)
</span>
<span>if __name__ == "__main__":
</span>    <span>with Pool() as pool:
</span>      result <span>= pool.map(cube, range(10,N))
</span>    <span>print("Program finished!")
</span>
これが私が今得ているものです:

何が起こったのですか?マルチプロセッシングは今では悪い選択であるようです。なぜ?

<span>from multiprocessing import Pool
</span><span>import time
</span><span>import math
</span>
N <span>= 5000000
</span>
<span>def cube(x):
</span>    <span>return math.sqrt(x)
</span>
<span>if __name__ == "__main__":
</span>    <span># first way, using multiprocessing
</span>    start_time <span>= time.perf_counter()
</span>    <span>with Pool() as pool:
</span>      result <span>= pool.map(cube, range(10,N))
</span>    finish_time <span>= time.perf_counter()
</span>    <span>print("Program finished in {} seconds - using multiprocessing".format(finish_time-start_time))
</span>    <span>print("---")
</span>    <span># second way, serial computation
</span>    start_time <span>= time.perf_counter()
</span>    result <span>= []
</span>    <span>for x in range(10,N):
</span>      result<span>.append(cube(x))
</span>    finish_time <span>= time.perf_counter()
</span>    <span>print("Program finished in {} seconds".format(finish_time-start_time))
</span>
プロセス間で計算を分割することで導入されたオーバーヘッドは、解決されたタスクと比較して大きすぎます。時間のパフォーマンスの観点からどれほどの違いがあるかを見ることができます。

結論

この記事では、Python Multiprocessingを使用して、Pythonコードのパフォーマンスの最適化について説明しました。

最初に、並列コンピューティングとは何か、それを使用するための主要なモデルを簡単に紹介しました。次に、マルチプロセッシングとその利点について話し始めました。最終的に、計算を並列化することが常に最良の選択ではないことがわかり、マルチプロセッシングモジュールはCPUバウンドタスクの並列化に使用する必要があることがわかりました。いつものように、それはあなたが直面している特定の問題を考慮し、異なる解決策の長所と短所に評価することの問題です。

私と同じように便利なPythonマルチプロセッシングについて学ぶことを見つけたことを願っています。 Pythonマルチプロセッシングと並列プログラミングに関するFAQ

Pythonでマルチプロセッシングを使用することの主な利点は何ですか?

​​

Pythonでマルチプロセッシングを使用することの主な利点は、複数のプロセスを同時に実行できることです。これは、CPU集約型タスクを操作する場合に特に有益です。これにより、プログラムはCPUの複数のコアを利用できるため、プログラムの速度と効率を大幅に改善できます。スレッドとは異なり、マルチプロセッシングはPythonのグローバルインタープリターロック(GIL)に苦しむことはありません。つまり、各プロセスは他のプロセスの影響を受けずに独立して実行できます。これにより、Pythonの並列プログラミングの強力なツールにマルチプロセッシングが行われます。同時に実行されます。各プロセスには、独自のPythonインタープリターとメモリスペースがあります。つまり、他のプロセスとは独立して実行できます。マルチプロセッシングモジュールは、これらのプロセスを簡単に作成および管理できるようにする多くのクラスと機能を提供します。たとえば、プロセスクラスは新しいプロセスを作成するために使用されますが、プールクラスはワーカープロセスのプールを管理するために使用されます。 > Pythonでのマルチプロセッシングとマルチスレッドの主な違いは、タスクの処理方法にあります。 Multiprocessingは各タスクの新しいプロセスを作成しますが、MultiThreadingは同じプロセス内で新しいスレッドを作成します。つまり、マルチプロセッシングは複数のCPUコアを最大限に活用できますが、マルチスレッドはPythonのグローバルインタープリターロック(GIL)によって制限されていることを意味します。これにより、一度に1つのスレッドのみが実行できます。ただし、マルチスレッドは、I/Oバウンドタスクに依然として役立ちます。プログラムは、ほとんどの時間を投入/出力操作が完了するのを待つのに費やしています。

Pythonのプロセス間でデータを共有するにはどうすればよいですか?

​​

マルチプロセッシングモジュールの共有メモリメカニズムを使用して、Pythonのプロセス間でデータを共有できます。これらには、それぞれ共有変数と配列を作成できる値クラスとアレイクラスが含まれます。ただし、各プロセスには独自のメモリ空間があるため、1つのプロセスで共有変数または配列に変更された変更は、マルチプロセッシングモジュールによって提供されるロックまたは他の同期プリミティブを使用して明示的に同期しない限り、他のプロセスに反映されないことに注意することが重要です。

マルチプロセッシング中にPythonでマルチプロセッシングを使用することの潜在的な落とし穴は何ですかPythonは、プログラムの速度と効率を大幅に向上させることができます。また、独自の課題も伴います。主な落とし穴の1つは、コードの複雑さの増加です。特に共有データと同期プロセスの処理に関しては、複数のプロセスを管理することは、シングルスレッドプログラムを管理するよりも複雑です。さらに、新しいプロセスを作成することは、新しいスレッドを作成するよりもリソース集約型であり、メモリ使用量の増加につながる可能性があります。最後に、すべてのタスクが並列化に適しているわけではなく、場合によっては、複数のプロセスの作成と管理のオーバーヘッドが潜在的なパフォーマンスの向上を上回る可能性があります。 pythonのマルチプロセッシングの例外は、子プロセスで発生する例外が親プロセスに自動的に伝播しないため、少し注意が必要です。ただし、マルチプロセッシングモジュールは、例外を処理するいくつかの方法を提供します。 1つの方法は、プロセスクラスのIS_ALIVE()メソッドを使用して、プロセスがまだ実行されているかどうかを確認することです。メソッドがfalseを返す場合、プロセスが終了したことを意味します。これは例外による可能性があります。別の方法は、プロセスクラスのExitcode属性を使用することです。これにより、プロセスが終了する理由に関する詳細情報を提供できます。他のPythonライブラリ。ただし、すべてのライブラリがマルチプロセッシング環境で使用されるように設計されているわけではないことに注意することが重要です。一部のライブラリは、スレッドセーフではない場合や、同時実行をサポートしていない場合があります。したがって、使用しているライブラリのドキュメントを確認して、マルチプロセスをサポートするかどうかを確認することをお勧めします。

Pythonでマルチプロセッシングプログラムをデバッグするにはどうすればよいですか?

​​

Pythonでマルチプロセッシングプログラムをデバッグするのは困難な場合があります。ただし、プログラムをデバッグするために使用できる手法がいくつかあります。 1つの方法は、印刷ステートメントまたはロギングを使用してプログラムの実行を追跡することです。別の方法は、PDBモジュールのset_trace()関数を使用して、コード内のブレークポイントを設定することです。また、マルチプロセスモジュールのlog_to_stderr()関数など、マルチプロセッシングをサポートする専門のデバッグツールを使用することもできます。これにより、プロセスのアクティビティを標準エラーにログに記録できます。オペレーティングシステム?

はい、さまざまなオペレーティングシステムでPythonでマルチプロセシングを使用できます。マルチプロセッシングモジュールは、標準のPythonライブラリの一部です。つまり、Pythonをサポートするすべてのプラットフォームで使用できます。ただし、マルチプロセッシングモジュールの動作は、プロセスの処理方法の違いにより、異なるオペレーティングシステム間でわずかに異なる場合があります。したがって、ターゲットオペレーティングシステムでプログラムをテストして、予想どおりに機能するようにすることをお勧めします。 Pythonでのマルチプロセシングの使用は、次のものを含みます。

- 可能な限りプロセス間でデータの共有を避けます。これは複雑な同期の問題につながる可能性があるためです。プロセスは、プロセスの作成と管理のプロセスを簡素化する高レベルのインターフェイスを提供するためです。

- プロセスクラスのJoin()メソッドを呼び出すことで、常にプロセスをクリーンアップします。 。

- プログラムが予期せずクラッシュするのを防ぐために例外を適切に処理します。

- プログラムが徹底的にテストして、マルチプロセッシング環境で正しく機能するようにします。

以上がPythonマルチプロセスと並列プログラミングのガイドの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。