Pythonでのプロセス、スレッド、コルーチンの使用について

説明文

最近、人工知能スケジューリングプラットフォームがPythonで開発されました。コンピューティング側はpython + tensorflowを使用するため、スケジューリング側も言語の異種混合セキュリティのためにpythonを選択しました。これには、スケジューリングの同時実行パフォーマンスの問題が含まれます。ビジネスニーズのために、それを実現できる必要があります。 1000+ qpsのトラフィック需要は、Pythonスケジューリングサービスのパフォーマンスに大きな課題を持っています。
特定のアーキテクチャを以下に示します。
Pythonでのプロセス、スレッド、コルーチンの使用について

補足:
アーキテクチャで使用されているpythonはcpythonであり、解釈と実行の言語はjpythonまたはpypythonではありません。cpythonのコミュニティ環境は比較的アクティブで、多くの開発キットがcensorの下に実装されています(tensorflow、numpyなど)。等
以下の議論はcpython言語です。

問題

各サービスは、タイプのデータを解析するための責任がある、と何の問題もなかったしている、とドッキングウィンドウの計算は、他のマシンにスケジュールすることができ、一時的なボトルネックがパフォーマンス構成するものではありません。現在、データコンピューティングサービス
予定の業務RPCサーバークライアント上で毎秒1000 +回を実行する必要がビジネスには、元のデータに一度RPCスケジューリングが含まれ、次に計算のためにコンピューティングサービスにRPCスケジューリングが含まれ、結果が返され、非同期ストレージが含まれます。このとき、Pythonを使用してさまざまな方法でRPC IOをスケジュールすると、パフォーマンスが異なります。

次のようなプロジェクトの実装と変換

順次実行

1,000以上のサービスが順番に実行されます。Pythonプログラムに1つのプロセスしかない場合、マシン上の他のプロセスがCPUリソースを獲得できません(どの言語のプロセスも、スレッド化せずに同時に1つのCPUコアしか使用できません。Python言語。プロセスがスレッドを開いた場合でも、同時に使用できるCPUコアは1つだけ、またはブロックされた状態の0を使用できます)、すべてのビジネスコードブロックは順番に実行され、インサイダーコードはCPUコアでのみ順番に実行できます。明らかにお勧めできません。ioが待機する必要のあるCPUは、実行を待機する必要があります。1つのタスクを実行して次にリサイクルして実行する後、パフォーマンスは低く、すべてのビジネスはシリアルです。

マルチスレッド実行

with concurrent.futures.ThreadPoolExecutor(max_workers=MAX_WOKERS) as executor:
        for (classify, sensorLists) in classifySensors.items():
            print(f'\ncurrent classify: {classify},  current sensors list: {sensorLists}')
            try:
                executor.submit(worker,classify,sensorLists)
            except Exception as e:
                print(e)

最初に、オペレーティングシステムのcpuカーネルがマルチスレッド/マルチプロセスをスケジュールする方法について簡単に説明します。マルチスレッド/マルチプロセスジョブスケジューリングは、オペレーティングシステムのカーネルレイヤーでスケジュールされます。オペレーティングシステムは、スレッド/プロセスの優先度またはタイムスライスを使い切るかブロックして、CPUタイムスライスを他のプロセス/スレッドに切り替えるかを決定します。一部のプロセス/スレッドは、ロックメカニズムなどに従ってCPUリソースをプリエンプトすることもできます。CPUがアイドルの場合、現在のスレッド/プロセスまたは、常にCPUコアを占有し、現在のPythonプロセス内のスレッドがCPUによって実行されるようにスケジュールされる方法について話し合うことができます。現在のマシンに複数のコアがあり、他のタスクが占有されていない場合、現在のスケジューリングサービスプロセスは複数のスレッドを使用します/スレッドプールはマルチスレッドビジネスジョブをスケジュールします。Pythonインタープリター言語により、現在のPythonプロセスでの各スレッドの実行は次のようになります
。1. GILロックを
取得2. CPUタイムスライスを取得
3.コードを実行し、ブロッキングを待機(スリープまたはブロックまたは時間のかかる操作)、または他のスレッドプリエンプションCPUタイムスライスIO
その4.リリースGILロックスイッチ スレッドの実行は、ステップ1から始まる繰り返します。
Pythonのスレッドが実行を希望していることがわかります。最初にGILロックを取得する必要があります。PythonプロセスにはGILロックが1つしかありません。
したがって、Pythonマルチスレッドの場合、解釈中の言語の特性により、追加のGILロックがあり、プロセスの複数のスレッドは同時に最大で1つのCPUリソースしか占有できませんが、待機中に別のスレッドに切り替えることができます。実行するには、前のスレッドioがシリアルを完了して次のスレッドに進むのを待つ必要はありません。そのため、マルチスレッドは現時点で同時に影響を与える可能性がありますが、同時に複数のCPUコアを占有することはできず、スレッドを並列に実行することはできません。別の同時実行時に、同時効果を実現するには、qpsがシリアル実行よりも優れています。

コルーチンの実行

プロセスとスレッドには、スケジューリング用のカーネルがあり、CPUタイムスライスの概念、プリエンプティブスケジューリング(複数のスケジューリングアルゴリズムを使用)、コルーチン(ユーザーレベルのスレッド)には、これはカーネルであるシステムに透過的です。コルーチンがあるかどうかはわかりません。コルーチンはユーザー自身のプログラムによって完全にスケジュールされています。これはユーザープログラムによって制御されるため、CPU制御に強制的に他のプロセス/スレッドに切り替えて強制的に実行させることは困難です。一般に、コラボレーティブスケジューリングのみを実行でき、他のコルーチンはコルーチンが制御を移した後にのみ実行できます。
Pythonはaysncを使用してコルーチンメソッドを定義し、メソッドの時間のかかる操作でawaitキーワードを定義します(これはユーザーが定義します)。実行がawaitに達したときに、他のコルーチンに切り替えて実行できるため、このpythonプロセスではこのCPUコアのコルーチンメソッドを複数回呼び出す必要がある場合、ユーザー定義のaysnc + await Ctripメソッドを介して、必要に応じて他のコルーチンにcpuタイムスライスを提供します。これにより、同時実行性の効果も得られます。切り替えのオーバーヘッドは比較的小さく、システムカーネルのメンテナンスとメンテナンススレッドが含まれていないため、シーンやその他の操作が保存されるため、Pythonで使用されるコルーチンが適切であれば、同時実行の効果はマルチスレッドよりも優れています。トルネードの基礎となるコルーチンの実装gen.coroutineデコレーター実装のソースコードを
参照して、コルーチンの基礎となる実装を理解することができ
ます。

Pythonのコルーチンの最下層は、イテレーターとジェネレーターの次のレイヤーによって切り替えられ、イベントはオペレーティングシステムによって提供される選択プールによって実現されます。ただし、Pythonのコルーチンの実装は、現在のプロセスまたは現在のスレッドでのみ切り替えることができ、同時に使用できるCPUコアは1つだけなので、並列処理を実現できません。

マルチプロセス実行

まず、オペレーティングシステムの前述のスレッド/プロセスのスケジューリング方法です。Pythonのスレッドを実行する場合、最初にGILロックを取得する必要があります。Pythonプロセスには1つのGILロックしかありません。次に、解釈実行言語pythonでマルチプロセスモードの設計を実行できます。プロセスの実行中に、メモリ空間の一部と独立したCPUコアを個別に適用できます。プロセス空間には一定の独立性があるため、各プロセスには独自の独立したGILロックがあります。 、Pythonマルチプロセスは並列効果を達成でき、qpsの効果はコルーチンおよびマルチスレッドよりもはるかに優れています。

マルチプロセス+コルーチン

マルチプロセスはCPUコアの数を最大限に活用でき、コルーチンはシングルコアの使用率をマイニングすることもできます。マルチプロセス+コルーチンモードのデバッグは異なる効果をもたらす可能性があります。コルーチン方式は一般にio集約型のアプリケーションで使用され、マルチプロセス方式は計算集約型のシナリオで使用され、マルチプロセス+コルーチン方式はIO集約型および計算集約型のシナリオで使用されます。私のプロジェクトでは、各タスクには2つのio、1つの計算が必要ですが、計算はすでに別のDockerのpythonプロセスにありますが、各タスクの計算時間は相変わらず連続しており、これも影響します全体的なqps効果、したがって、現時点ではマルチプロセス+コルーチンを使用するのが最適です。あるタイプのIOTデバイスのビジネスは独立したプロセスに配置され、複数のタイプのIOTデバイスのビジネスを並行して実行できます。このタイプのiOTデバイスの複数のデバイスコルーチンを介して同時実行できるため、全体的なqps効果は良好です。

ダファ・ゴルーティン

本質的に、ゴルーチンはコルーチンです。違いは、Golangがランタイムやシステムコールなどの多くの側面でゴルーチンスケジュールをカプセル化して処理することです。長時間の実行に遭遇したり、システムコールを行ったりすると、現在のゴルーチンのCPU(P)をアクティブに転送して、他のゴルーチンを許可しますスケジュールして実行することができます。つまり、Golangは言語レベルからコルーチンをサポートしています。Golangの主な機能は、言語レベルからのコルーチンのネイティブサポートです。関数またはメソッドの前にgoキーワードを追加すると、コルーチンを作成できます。
goの定義はより複雑で、Pythonコルーチンよりも、コルーチンをオペレーティングシステムの異なるスレッドでスケジュールすることができます。
したがって、パフォーマンスを追求したい場合は、スケジューリングサーバーがgolangでリファクタリングされます。
goの参考資料:
「Golang study notes two」電子書籍
Golang GMPスケジューリングモデルhttps://blog.csdn.net/qq_37858332/article/details/100689667
Golangのコルーチンの詳細な説明https://blog.csdn.net/weixin_30416497/記事/詳細/ 96665770

分散変換

上記の方法はすべて、スケジューリングサーバーの単一ノードの同時実行機能から変更されていますが、どのような状況でもパフォーマンス要件を満たせず、単一サーバーのパフォーマンスが向上する場合は、分散変換を実行する必要があります。コンピューティングノードの分散変換は比較的単純です。k8s上の同じマシンに直接ディスパッチされます。問題はディスパッチサーバーにあります。ディスパッチサーバーは、クライアントの要求とrpc ioの配布に似ています。現在のモードは、クライアントのサービスクライアントのディスパッチです。メモリ番号構造で、サービスノード情報->直接接続されたノードを取得してサービスリクエストを実行します。分散変換を実行する場合は、ビジネスを複数のスケジューリングサービスクライアントに分割して、rpc ioリクエストのロードと配信を実行する必要があります。ビジネスディメンションに応じて、スケジューリングサービスクライアントを介して一部のタイプのIoTデバイスを分割し、他のスケジューリングサービスクライアントを介してIoTデバイスの他の部分を分割するか、またはスケジューリングサービスクライアントをステートレス要求ディストリビューターに合理化します。ゲートウェイが事前に決定されている限り、複数をデプロイできます ルーティング配布ルールを定義し、正しいサーバーにrpc io要求を送信します。2つの違いは次のとおりです
。1つは複数のスケジューリングサービスクライアント(このクライアントのビジネス配布ルーティングロジック)->複数のコンピューティングサービス
もう1つ:複数のステートレス要求ディストリビューター(ステートレス、何もなし)ビジネス配布ルーティングロジック)->ビジネスルーティングゲートウェイ->複数のコンピューティングサービス
最初の可能なスケジューリングサービスクライアントは異なる構成をロードします。つまり、ロードされたビジネス配布ルーティング構成ロジックは異なり、2番目はステートレスです。リクエストディストリビューターは同じですが、ルーティングゲートウェイを維持する必要があります(使用するrpcに応じて、grpcなどの公式ゲートウェイとオプションのNginxマッチングゲートウェイがあり、ゲートウェイにルーティング構成を動的に追加して、ゲートウェイを自動的に書き換えることができます構成、再読み込み)
分散変換は上記のように完了し、複数のスケジューリングサービスクライアントまたは複数のステートレス要求ディストリビューター+ビジネスルーティングゲートウェイに変換できます。もちろん、両方のモードで、サービスの登録とサービスにzkまたはetcdが必要です複数のクライアントまたはディストリビューターが対応するコンピューティングサーバーのリソース情報をzkまたはetcdから直接取得することがわかりました。具体的な変換モードは次のとおりです。
最初の:
Pythonでのプロセス、スレッド、コルーチンの使用について

第二種:

Pythonでのプロセス、スレッド、コルーチンの使用について

まとめ

1. Pythonでは、プロセスには複数のスレッドがあります。多くても、同時に使用できるコアは1つだけです。コルーチンを使用する場合、同時に使用できるコアは1つだけです
。2.Pythonマルチプロセスは、複数のCPUコア、1つのpythonfを使用できますサービスシステムでさまざまなサービスを実行するには、処理プロセスを実行することをお勧めします。そうしないと、マルチコアCPUパフォーマンスを使用できず、サービスシステム自体の同時実行機能を実現できません。
3. java、goなどの他の言語プロセスは、複数のスレッドまたは複数のコルーチンが開かれるときに、同時に複数のコアを使用できます。go言語は、本質的にコルーチン属性を備えており、オペレーティングシステムの異なるスレッドでスケジュールできます。コルーチン。
4.サービスパフォーマンスの変換により、単一ノードの同時パフォーマンスが向上します。パフォーマンスを向上させる場合、さまざまな段階でストレステストを実行してパフォーマンスのボトルネックを特定し、パフォーマンスの向上を目標とするか、システム分散システムの変換を実行して複数のサーバーを展開します複数のノードが負荷をかけて業務を遂行し、同時実行性を向上させます。分散すると、いくつかのコンポーネントが追加され、一部のコンポーネントで単一障害点が発生したり、サービスの一貫性、データの一貫性などの問題を考慮する必要があります。

おすすめ

転載: blog.51cto.com/7142665/2486598