1

しばらくの間、私を悩ませてきたパフォーマンスの最適化の問題があります。私はそれからより多くのパフォーマンスを絞り出そうとしましたが、あまり成功しませんでした.

システム(簡略化)は次のとおりです。

1) リクエストは HTTP Post 経由で受信されます (同期/インラインで応答する必要があります)

2) リクエストを処理し、レスポンスを返す (すべて XML)

3) 15 秒以内に結果の準備ができていない場合は、「サーバーがビジーです。後で試してください」タイプのメッセージで応答します。

中央のメッセージ処理メカニズムとして、メッセージをキューに入れ、開始し、待機するタスクベースのアプローチを使用しました (最大 15 秒)。

メッセージがほぼ瞬時に処理される場合、スループット (1 秒あたりの要求数) は非常に良好です (1000/秒)。ただし、メッセージ処理が 200 ミリ秒遅れると、これはかなりひどく 40/s に低下します。

いくつかのスニペット:

    public void AddMessage()
    {
         Task.Factory.StartNew(() =>
                    {
                        worker.ProcessMessage(); を返します。
                    };
    }

    public MessageResponse GetResult()
            {
                task.Task.Wait(15 * 1000);

                スイッチ (タスク.ステータス)
                {
                    ケース TaskStatus.Running:
                            message = "リクエストに通常より時間がかかっています"
                       壊す;
                    ケース TaskStatus.RanToCompletion:
                            メッセージ = (MessageResponse) task.Result;
                        壊す;
                }
       メッセージを返します。
    }


ノート:

タスク作成オプション None / Longrunning / PreferFairness は影響しません。ビジュアル スタジオ パフォーマンス アナライザーを実行すると、Longrunning が要求ごとに新しいスレッドを作成し (予想される)、None が限られた数 (基になるスレッドプール) を使用して要求を処理することが視覚的にわかります。

ANTS パフォーマンス プロファイラーと Visual Studio パフォーマンス アナライザーの両方を見ると、競合に関する同時実行の問題はなく、時間が浪費されている他の明白な領域 (CPU 時間またはウォール クロック時間) もありません。

視覚化された結果から明らかなことは、たとえば 1000 のリクエストがキューに入れられている状況では、プログラム時間の 90% がスレッド サービスとコンテキスト切り替えに費やされていることです。

(明らかに非常に高価です)。私の結論は、(複数のリクエストで)結果を待つことは非常にコストがかかるということです。

WebページまたはWPFフォームでこれを行うと、完全に非同期にすることができますが、このオプションはありません。

同時実行性を最適化するためにメッセージ処理メカニズムを変更できる場所はありますか? 私は本当に何に対してもオープンであり、それが有益であれば async / await を探求することさえあります。

前もって感謝します :)

4

1 に答える 1

3

リクエストごとに 2 つのスレッドを使用するため、パフォーマンスが低下していると思います。

あなたはasync/に対してオープンであると述べているのでawait、私は次のようなことを試みます:

public async Task<MessageResponse> GetResult(Message message)
{
  var cts = new CancellationTokenSource(TimeSpan.FromSeconds(15));
  try
  {
    return await Task.Run(() => worker.ProcessMessage(message, cts.Token));
  }
  catch (OperationCanceledException)
  {
    return "Your request is taking longer than usual";
  }
}

ProcessMessageまた、定期的に呼び出すように変更する必要がありますCancellationToken.ThrowIfCancellationRequested。また、メッセージ処理が CPU バウンドではなく I/O バウンドの場合は、 に変更ProcessMessageする必要がありますasync

于 2013-03-28T15:36:22.983 に答える