0

サード パーティの REST サービスへの多くの要求を必要とするアプリケーションがあります。アプリケーションのこの部分を変更してリクエストを非同期に行うと、速度が向上する可能性があると考えたので、POC コンソール アプリケーションを作成してテストしました。

驚いたことに、非同期コードの完了には、同期バージョンの約 2 倍の時間がかかりました。私はそれを間違っているだけですか?

async static void LoadUrlsAsync() 
{
    var startTime = DateTime.Now;
    Console.WriteLine("LoadUrlsAsync Start - {0}", startTime);


    var numberOfRequest = 3;
    var tasks = new List<Task<string>>();

    for (int i = 0; i < numberOfRequest; i++)
    {
        var request = WebRequest.Create(@"http://www.google.com/images/srpr/logo11w.png") as HttpWebRequest;
        request.Method = "GET";

        var task = LoadUrlAsync(request);
        tasks.Add(task);
    }

    var results = await Task.WhenAll(tasks);

    var stopTime = DateTime.Now;
    var duration = (stopTime - startTime);
    Console.WriteLine("LoadUrlsAsync Complete - {0}", stopTime);
    Console.WriteLine("LoadUrlsAsync Duration - {0}ms", duration);
}

async static Task<string> LoadUrlAsync(WebRequest request)
{
    string value = string.Empty;
    using (var response = await request.GetResponseAsync())
    using (var responseStream = response.GetResponseStream())
    using (var reader = new StreamReader(responseStream))
    {
        value = reader.ReadToEnd();
        Console.WriteLine("{0} - Bytes: {1}", request.RequestUri, value.Length);
    }

    return value;
}

注: また、system.net 接続プールからスロットリングを排除するために、app.config でmaxconnections=100を設定しようとしました。この設定は、パフォーマンスに影響を与えないようです。

  <system.net>
    <connectionManagement>
      <add address="*" maxconnection="100" />
    </connectionManagement>
  </system.net>
4

4 に答える 4

2

非同期バージョンは、スレッド数を増やすと高速になります。確かではありませんが、スレッドをセットアップするコストを回避していると思います。このしきい値を超えると、非同期バージョンが優れたものになります。50 または 500 のリクエストを試してみると、非同期の方が高速であることがわかるはずです。それが私にとってうまくいった方法です。

500 Async Requests:  11.133 seconds
500 Sync Requests:   18.136 seconds

呼び出しが 3 回までしかない場合は、非同期を避けることをお勧めします。これが私がテストに使用したものです:

public class SeperateClass
{
    static int numberOfRequest = 500;
    public async static void LoadUrlsAsync()
    {
        var startTime = DateTime.Now;
        Console.WriteLine("LoadUrlsAsync Start - {0}", startTime);

        var tasks = new List<Task<string>>();

        for (int i = 0; i < numberOfRequest; i++)
        {
            var request = WebRequest.Create(@"http://www.google.com/images/srpr/logo11w.png") as HttpWebRequest;
            request.Method = "GET";

            var task = LoadUrlAsync(request);
            tasks.Add(task);
        }

        var results = await Task.WhenAll(tasks);

        var stopTime = DateTime.Now;
        var duration = (stopTime - startTime);
        Console.WriteLine("LoadUrlsAsync Complete - {0}", stopTime);
        Console.WriteLine("LoadUrlsAsync Duration - {0}ms", duration);
    }

    async static Task<string> LoadUrlAsync(WebRequest request)
    {
        string value = string.Empty;
        using (var response = await request.GetResponseAsync())
        using (var responseStream = response.GetResponseStream())
        using (var reader = new StreamReader(responseStream))
        {
            value = reader.ReadToEnd();
            Console.WriteLine("{0} - Bytes: {1}", request.RequestUri, value.Length);
        }

        return value;
    }
}

public class SeperateClassSync
{
    static int numberOfRequest = 500;
    public async static void LoadUrlsSync()
    {
        var startTime = DateTime.Now;
        Console.WriteLine("LoadUrlsSync Start - {0}", startTime);

        var tasks = new List<Task<string>>();

        for (int i = 0; i < numberOfRequest; i++)
        {
            var request = WebRequest.Create(@"http://www.google.com/images/srpr/logo11w.png") as HttpWebRequest;
            request.Method = "GET";

            var task = LoadUrlSync(request);
            tasks.Add(task);
        }

        var results = await Task.WhenAll(tasks);

        var stopTime = DateTime.Now;
        var duration = (stopTime - startTime);
        Console.WriteLine("LoadUrlsSync Complete - {0}", stopTime);
        Console.WriteLine("LoadUrlsSync Duration - {0}ms", duration);
    }

    async static Task<string> LoadUrlSync(WebRequest request)
    {
        string value = string.Empty;
        using (var response = request.GetResponse())//Still async FW, just changed to Sync call here
        using (var responseStream = response.GetResponseStream())
        using (var reader = new StreamReader(responseStream))
        {
            value = reader.ReadToEnd();
            Console.WriteLine("{0} - Bytes: {1}", request.RequestUri, value.Length);
        }

        return value;
    }
}

class Program
{
    static void Main(string[] args)
    {
        SeperateClass.LoadUrlsAsync();
        Console.ReadLine();//record result and run again

        SeperateClassSync.LoadUrlsSync();
        Console.ReadLine();
    }
}
于 2013-10-29T20:18:23.707 に答える
0

私のテストではWebRequest.GetResponseAsync()、3 つの並列リクエストに対してメソッドを使用する方が高速です。

これは、大規模なリクエスト、多数のリクエスト (3 は多くない)、および別の Web サイトからのリクエストでより顕著になるはずです。

あなたが得ている正確な結果は何ですか?あなたの質問では、TimeSpan を文字列に変換してミリ秒と呼んでいますが、実際にはミリ秒を計算していません。秒の端数を表示する標準の TimeSpan.ToString を表示しています。

于 2013-10-29T20:18:40.653 に答える
-1

問題は何よりも環境問題だったようです。コードを別のネットワーク上の別のマシンに移動すると、結果は期待どおりになりました。

実際、元の非同期コードは、同期バージョンよりも高速に実行されます。これにより、期待されるパフォーマンスの向上なしに、アプリケーションに追加の複雑さを導入していないことを確認できます。

于 2013-10-29T21:23:37.390 に答える