同时向同一个http主机发送多个请求

时间:2015-10-03 04:39:42

标签: c# .net http asynchronous

我有一个C#桌面应用程序,它需要同时向同一个Web服务器发出多个http请求。这是我为检查我的请求是否确实同时发生而进行的测试:

  1. 在Web服务器上,创建一个休眠3秒的测试页(模拟一些长时间运行的任务),然后返回当前日期/时间。这是代码(VB.Net):

    <%system.threading.thread.sleep(3000)%GT;<%=现在%GT;

  2. 在C#app中,我有一个函数MakeRequest(),它使用System.Net.Http.HttpClient发出Web请求,并以字符串形式返回响应。

  3. 然后在C#app中有一个按钮点击调用的函数,它异步调用MakeRequest()多次:

    var responses = await Task.WhenAll(MakeRequest(),MakeRequest(),MakeRequest());

  4. 在上面的例子中,MakeRequest()被调用3次。当我监视请求/秒性能计数器时,我在Web服务器上看到的是,它获得2个请求,然后3秒后再增加1个请求。这是设计的,因为System.Net.ServicePointManager.DefaultConnectionLimit的默认值是2,所以我的C#app一次只能发送2个请求,虽然我要求3. C#app完成按钮点击的总时间是6秒。

    现在在C#应用程序中,我设置了ServicePointManager.DefaultConnectionLimit = 1000000.此时Web服务器上的Requests / sec显示3,并且C#应用程序中的按钮单击在3秒内完成。到目前为止一切都很好。

    接下来,我将C#应用更改为同时进行60次呼叫,而不是3次。这就是事情变得有趣的地方。当我点击按钮时,我希望Web服务器上的Requests / sec能够达到60,而C#app会在3秒内完成按钮点击。我得到的是网络服务器请求/秒显示类似5,3秒后5等等,直到所有60个请求都已完成。当我再次单击该按钮时,相同的图片除了Requests / sec spike to 10或15之外,按钮点击显然更快完成。再次单击 - 此时请求/秒显示两个尖峰到30,按钮单击在6秒内完成。随后的按钮点击导致请求/秒尖峰首先到40然后到20(总共60个请求),然后是50和10,然后是55和5,最终我的C#应用​​程序开始一次性发送所有60个请求。按钮单击在3秒内完成,Web服务器上的请求/秒显示一个峰值为60.如果我继续按下按钮,我将始终同时收到所有60个请求。

    但这不是全部。如果我停止按下按钮,我的C#应用​​程序似乎“忘记”它是以前的成就。我没有重新启动应用程序,只是停止按下按钮一会儿,然后在下一次按下时我一次又回到5个请求,如果我继续按下按钮,上面的情况会重复。

    我还从MVC执行了上述测试 - 只是将代码从C#app复制并粘贴到MVC页面。得到了完全相同的结果。

    任何人都可以解释一下发生了什么吗?谢谢

    这是C#应用程序的代码。它是一个WinForms应用程序,代码存在于Form类中:

    <!-- language: lang-c# -->
    private HttpClient _httpClient = new HttpClient();
    
    private async void button1_Click(object sender, EventArgs e)
    {
        ServicePointManager.DefaultConnectionLimit = 1000000;
    
        var sw = Stopwatch.StartNew();
        var responses = await Task.WhenAll(MakeRequest(), MakeRequest(), MakeRequest());
        sw.Stop();
    
        var msg = String.Join("\r\n", responses) + "\r\n\r\nTime Elapsed: " + sw.ElapsedMilliseconds;
        MessageBox.Show(msg);
    }
    
    private async Task<string> MakeRequest()
    {
        using (var message = await _httpClient.GetAsync("http://TestServer/TestPage.aspx"))
        {
            return await message.Content.ReadAsStringAsync();
        }
    }
    

1 个答案:

答案 0 :(得分:1)

有两个原因:

  1. 客户端Windows SKU将并发IIS请求数限制为10个。
  2. 显然,您的客户端使用同步IO或以其他方式阻止。让线程池变热需要一段时间。线程仅在一段时间内注入。要么使用异步IO并且是非阻塞的,要么确保您需要的线程实际存在。关于“遗忘”:空闲池线程随着时间的推移而退役。因此,您的测试对时间敏感。非常不可靠,不要将其投入生产。