C# 为什么异步WebRequests的这种实现比同步实现慢?

C# 为什么异步WebRequests的这种实现比同步实现慢?,c#,performance,asynchronous,httpwebrequest,async-await,C#,Performance,Asynchronous,Httpwebrequest,Async Await,我有一个应用程序需要向第三方REST服务发出许多请求。我认为修改应用程序的这一部分以异步方式发出请求可能会加快速度,因此我编写了一个POC控制台应用程序来进行测试 令我惊讶的是,异步代码的完成时间几乎是同步版本的两倍。我只是做错了吗 async static void LoadUrlsAsync() { var startTime = DateTime.Now; Console.WriteLine("LoadUrlsAsync Start - {0}", startTime);

我有一个应用程序需要向第三方REST服务发出许多请求。我认为修改应用程序的这一部分以异步方式发出请求可能会加快速度,因此我编写了一个POC控制台应用程序来进行测试

令我惊讶的是,异步代码的完成时间几乎是同步版本的两倍。我只是做错了吗

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;
}
异步静态void LoadUrlsAsync()
{
var startTime=DateTime.Now;
WriteLine(“loadurlsasyncstart-{0}”,startTime);
var numberOfRequest=3;
var tasks=新列表();
for(int i=0;i
注: 我还尝试在app.config中设置maxconnections=100,以消除system.net连接池中的节流。此设置似乎不会对性能产生影响

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

随着线程数量的增加,异步版本会变得更快。我不确定,但是我的猜测是您绕过了设置线程的成本。当您超过此阈值时,异步版本将变得更高级。尝试50个甚至500个请求,您应该会发现async更快。对我来说就是这样

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();
    }
}
public类separateclass
{
静态int numberOfRequest=500;
公共异步静态void LoadUrlsAsync()
{
var startTime=DateTime.Now;
WriteLine(“loadurlsasyncstart-{0}”,startTime);
var tasks=新列表();
for(int i=0;i
随着线程数量的增加,异步版本会变得更快。我不确定,但是我的猜测是您绕过了设置线程的成本。当您超过此阈值时,异步版本将变得更高级。尝试50个甚至500个请求,您应该会发现async更快。对我来说就是这样

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();
    }
}
public类separateclass
{
静态int numberOfRequest=500;
公共异步静态void LoadUrlsAsync()
{
var startTime=DateTime.Now;
WriteLine(“loadurlsasyncstart-{0}”,startTime);
var tasks=新列表();
for(int i=0;i