Pythonスレッドとサブフローの説明

3711 ワード

デフォルトでは、Pythonの実行は、グローバル解釈ロック(GIL)によってトラフィック制御されるスレッドで実行されます.ほとんどの場合、これは大きなボトルネックではありませんが、多くのジョブを並列に実行するとボトルネックになります.
Pythonは、スレッドとマルチプロセッサの2つの方法を提供しています.各オプションでは、長期にわたって実行される作業を並列バッチに分割し、並列に実行できます.
[InfoWorldのポイント:Anacondaの使用を開始します.これはデータ科学のPythonリリースです.•PythonのAnacondaリリースの新機能です.•データ科学のための基本的なPythonツール5つ-現在改良されています.|InfoWorldのApp Dev Reportニュース通信でプログラミングの話題を知ります.]
関連する作業によっては、操作速度を大幅に速めることがある.少なくとも、完了を待つ間に他の作業をブロックしないという方法でタスクを処理できます.
本稿では,Pythonでスレッドとサブプロセスを使用する最も速い方法の1つ,すなわちスレッドとプロセスプールについて検討する.
PythonスレッドとPythonプロセス
Pythonスレッドは、互いに独立して動作する作業ユニットです.ただし、CPU上のハードウェアスレッドには対応しません.少なくともCPythonでは対応しません.PythonスレッドはGILによって制御されるため、シリアルで実行できます.一度に1つのPythonスレッドしか実行できないため、待機中のタスクを組織するための有用な方法です.例えば、スレッドBが外部システムからの応答を待つ場合、Pythonは、スレッドAまたはスレッドCを実行することができる.
Pythonプロセスは、独立して実行されるPythonインタプリタのインスタンス全体です.各Pythonプロセスには、独自のGILと処理するデータのコピーがあります.これは、複数のPythonプロセスが個別のハードウェアカーネル上で並列に実行できることを意味します.その代わり、Pythonプロセスの起動時間はPythonスレッドの起動時間よりも長い.
PythonスレッドとPythonプロセスの間で選択する方法は次のとおりです.
  • 長時間実行するI/Oバインディング操作を実行する場合、Pythonの外部でサービスを待つタスク(例えば、複数の並列Webキャプチャまたはファイル処理ジョブ)がスレッドを使用する.
  • Cによって作成された外部ライブラリ(例えばNumPy)で処理される長時間実行されるCPUバインド操作を実行している場合は、スレッドを使用します(ここの作業もPythonの外部で完了しているため).
  • Pythonで長時間実行するCPUバインド操作を実行する場合は、プロセスを使用します.

  • PythonスレッドプールとPythonプロセスプール
    PythonスレッドとPythonプロセスを使用して複数のジョブを処理する最も簡単な方法は、PythonのPoolオブジェクトを使用することです.Poolでは、スレッドまたはプロセスのセット(選択)を定義できます.完了順に結果を返す任意の数のジョブを提供できます.
    たとえば、1から100までの数値リストからURLを構築し、並列に取得します.この例はI/Oによって制約されるため、スレッドまたはプロセスの使用間に明らかなパフォーマンスの違いはないかもしれないが、基本的な考え方は明らかであるべきである.
    # Python 3.5+
    from multiprocessing.dummy import Pool as ThreadPool from multiprocessing import Pool as ProcessPool from urllib.request import urlopen def run_tasks(function, args, pool, chunk_size=None): results = pool.map(function, args, chunk_size) return results def work(n): with urlopen("https://www.google.com/#{n}") as f: contents = f.read(32) return contents if __name__ == '__main__': numbers = [x for x in range(1,100)] # Run the task using a thread pool t_p = ThreadPool() result = run_tasks(work, numbers, t_p) print (result) t_p.close() # Run the task using a process pool p_p = ProcessPool() result = run_tasks(work, numbers, p_p) print (result) p_p.close()

    Pythonマルチプロセッシング例
    上記の例では、次のように動作します.multiprocessingモジュールは、スレッド(multiprocessing.dummy)およびプロセス(multiprocessing)にプールオブジェクトを提供する.multiprocessingを使用することについては、同じスレッドとサブプロセスAPIを持つことが好ましいので、以下に示すように、両者と交換して使用できる関数を作成できます.t_pおよびp_pは、実施例ThreadPoolおよびProcessPoolである.両方とも、タスク用のプールタイプとしてrun_tasksに渡される.デフォルトでは、各プールインスタンスは、使用可能なCPUコアごとにスレッドまたはプロセスを使用します.プールの作成には一定のコストがかかりますので、過度に使用しないでください.大量のジョブを長時間処理する場合は、完了するまでプールを作成してから処理します..close()関数を呼び出すことで、プールを処理できます.pool.map()は、作品を細分化するための関数です.pool.map()は、パラメータリスト付きの関数を受け入れて、その関数の各インスタンスに適用し、作業を複数のブロックに分割し(ブロックサイズを指定できます.デフォルトでは通常良いです)、各ブロックを作業スレッドまたはプロセスに供給します.
    通常、mapは実行中のスレッドをブロックします.これは、mapが完了した作業に戻る前に、他の操作を実行できないことを意味します.mapを非同期で実行する場合は、すべてのジョブが完了したときに実行されるコールバック関数を指定します.map_asyncを使用します.
    最後に、この基本例は、それぞれのステータスを持つスレッドおよびプロセスにのみ関連します.スレッドまたはプロセスが互いに情報を共有する必要があるCPUバインド操作が長期にわたって実行されている場合は、共有メモリまたはサーバプロセスに対してマルチプロセッサを使用することを考慮してください.
    総じて、処理するデータと処理するデータをパーティション化すればするほど、すべてのコンテンツの実行速度が速くなります.どの言語を使用しても、これはマルチプロセッサとマルチスレッドの基本ルールです.
    From: https://www.infoworld.com/article/3315121/python-threading-and-subprocesses-explained.html