さまざまなサードパーティ API を呼び出してデータを収集する必要があるコンソール アプリケーション (c#) があります。これは、異なるユーザーに対して同時に行う必要があります。そのためにスレッドを使用しています。しかし、ユーザー数が増加するにつれ、このサービスは CPU パフォーマンスを圧迫しています。他のプロセスに影響を与えています。並列処理にスレッドを使用できるが、CPU パフォーマンスに大きな影響を与えない方法はありますか?
2 に答える
あなたの質問から、スレッドを手動で作成していると思います。これに答える簡単な方法は、Task Parallel Libraryのような API を使用することを提案することです。それらを処理するためのスレッドの数 - したがって、500 の API リクエストが与えられた場合、数スレッドに制限されます。
ただし、より詳細に答えると、この問題が発生する一般的な理由は、コードが作成するスレッドが多すぎることです。スレッドは無料のリソースではなく、高価です。
あなたの質問に基づいて作成された例は次のとおりです。
- 呼び出す必要がある 5 つのサードパーティ API があり、それぞれがユーザーごとに最大 1 MB のデータを返します
- ユーザーごとに、個別のバックグラウンド スレッドで各 API を呼び出します。
- 100 人のユーザーがいます
- したがって、合計で 500 のスレッドが作成され、それぞれがネットワークからのデータを待機しています。
ここでの問題は、プログラムが管理しようとしているスレッドが 500 あり、それらはすべてシステムの最も遅い部分であるネットワークで待機していることです。
もっと簡単に言えば、一度に 1 つずつダウンロードするのではなく、一度に 500 個のデータをダウンロードしようとしています (この例では、すべてがゆっくりと終了することを意味します)。各スレッドは何もしない (ネットワークを待機するだけ) ため、CPU はアイドル状態のスレッドを継続的に切り替えます。ユーザー数を増やすと、スレッドの数が増えます。これにより、実際には各スレッドのダウンロードが遅くなりますが、スレッド間の切り替えのためだけに CPU 使用率が増加します。これが (おおよそ) ユーザー数が増えるにつれてパフォーマンスが低下する理由です。
より良い例は、同じシナリオを採用し、バックグラウンド スレッドを 1 つだけ使用することです。
- 呼び出す必要がある 5 つのサードパーティ API があり、それぞれがユーザーごとに最大 1 MB のデータを返します
- 各 API 呼び出しはキューに入れられ、キューは単一のスレッドによって処理されます
- 100 人のユーザーがいます
- したがって、バックグラウンドで実行されている 1 つのスレッドがあり、各リクエストに対してネットワークの利用可能な帯域幅をすべて使用しています。
この例では、CPU 使用率はほぼ一定です。ユーザーの数に関係なく、実行中のバックグラウンド スレッドは 1 つだけなので、コンテキストの切り替えは最小限に抑えられます。個々の API 呼び出しは、ネットワーク カードの最大レートで実行されるため、できるだけ早く終了します。
現実には、おそらく 1 つのスレッドでは十分ではありません。別の場所に制限要因があるため、1 つの要求でネットワークが飽和状態になることはほとんどありません。ただし、これは後で調整できるものです。おそらく 2 つまたは 3 つのスレッドの方がパフォーマンスは高くなりますが、4 つのスレッドではさらに遅くなります。スレッド化の一般的なルールは、作品ごとにスレッドを作成するのではなく、小さく始めて作業を進めることです。