5

これがシナリオです。IIS によってホストされるゲートウェイ。リクエストは、別のサービスに対して複数の独立した他のリクエストを発行する必要がある場合があり、それぞれに最大数秒かかる場合があります。当然、並列化の有力候補だと思いました。ただし、それを行うべきかどうか、また行う場合は、どの程度の並列処理を使用する必要があるかについて、内部で苦労しています。私の懸念は、アプリ内のすべてのスレッドが一般に .net スレッド プールによって管理されることです。そのため、あまりにも多くのスレッドを割り当ててしまうと (待機していても)、他のゲートウェイ機能や API を窒息させてしまう可能性がありますか?

4

2 に答える 2

8

PLINQは、あなたの場合ではない計算にバインドされた操作に役立ちます。あなたにとって理にかなっているのは非同期I/Oです。

.NETで非同期I/Oを実行するには、複数の方法があります。プレーンな古いAPMTPLReactive ExtensionsC#5 async / awaitF#非同期ワークフローです。後者の3つの手法を使用すると、さまざまな方法で複数のI / O操作を構成し、ボイラープレートコードの量を減らすことができます。

非同期I/Oは、新しいスレッドを割り当てることではありません。I / O完了ポートを使用して、応答の待機中のスレッドのブロックを回避します。

これを強調する必要があります。非同期I/Oを使用して、既に並行環境(IIS)で複数の長時間実行要求を作成すると、スループットとスレッドプールの使用率が確実に向上します。

のコードを検討してください。

Task.Factory.StartNew( () => Parallel.ForEach<Item>(items, item => DoSomething(item)));

クライアント側のプログラムで使用すると、UIスレッドをブロックせずに、内部でDoSomething非同期にI/Oを実行する必要がなくなります。

すでに並行サービスがあり、DoSomethingI / Oを同期的に実行すると、ビジープールで追加のブロックされたスレッドを使用することになります。着信リクエストごとに3つの発信リクエストを並行して同期的に実行する場合、10の同時着信リクエストはプール上の30のスレッドをブロックします。これはあまりスケーラブルなアプローチではありません。

I / Oバウンドのタスクがある場合、タスクが新しいスレッドでスケジュールされているかどうかは重要ではありません。重要なのは、このタスクがスレッドをブロックするかどうかです。

したがって、TPLを使用すると、次のパターンが上記のコードよりも優れていることがわかります。

var tasks = new Task<System.Net.WebResponse>[2];
var urls = new string[] { "https://stackoverflow.com/", "http://google.com/" };
for (int i = 0; i < tasks.Length; i++)
{
    var wr = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(urls[i]);
    tasks[i] = Task.Factory.FromAsync<System.Net.WebResponse>(
                   wr.BeginGetResponse,
                   wr.EndGetResponse,
                   null);
}

var result = Task.Factory.ContinueWhenAll(
    tasks,
    results => {
        foreach (var result in results)
        {
            var resp = result.Result.GetResponseStream();
            // Process responses and combine them into single result
        }
    });

繰り返しますが、上記のコードの90%は定型文です。重要な機能はWebRequestのBeginGetResponse非同期操作であり、最終的に得られる高レベルの手法(TPL、Rxなど)に関係なく使用する必要があります。

于 2013-03-19T05:31:42.253 に答える
3

あなたの懸念はある程度有効です。実際、スレッドプールは圧倒される可能性があります。これが、実行時間の長い非コンピューティング IO 関数を呼び出すようなゲートウェイ サービスが一般に非同期であることが好まれる理由です。非同期は、「起動して忘れる」という意味ではありません。この待機によってスレッドがブロックされることはなくなりますが、「待機」することはできます。

これには、大幅なコード変更が必要です。

はるかに簡単な解決策は、負荷ジェネレーターをサービスに配置し、それが問題であるかどうかを測定することです。はいの場合、簡単な修正は、スレッドプールのサイズを大幅に増やすことです (私は 500 ~ 1000 スレッド (デフォルト = 250) の経験があります)。これはスループットにとって最適ではありませんが、機能し、信頼性が高く、開発者の時間もほとんどかかりません。負荷をかけた状態でテストして、夜間に厄介なページャー呼び出しが発生しないようにしてください.

非同期は現在大流行していますが、開発者の生産性に関しては欠点があることに注意してください。場合によっては、何百ものスレッドを生成するという古き良きソリューションで十分であり、実際にはエンジニアリング上の最善のトレードオフです。C# 5.0 を使用している場合は、async/awaitノンブロッキング IO をより簡単に利用して実現できます。

于 2013-03-19T09:08:11.373 に答える