Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/338.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 对同一http主机的多个同时请求_C#_.net_Http_Asynchronous - Fatal编程技术网

C# 对同一http主机的多个同时请求

C# 对同一http主机的多个同时请求,c#,.net,http,asynchronous,C#,.net,Http,Asynchronous,我有一个C#桌面应用程序,它需要同时向同一个web服务器发出多个http请求。下面是我执行的测试,以检查我的请求是否确实同时发生: 在web服务器上,创建一个休眠3秒的测试页面(模拟一些长时间运行的任务),然后返回当前日期/时间。下面是代码(VB.Net): 在C#应用程序中,我有一个函数MakeRequest(),它使用System.Net.Http.HttpClient发出web请求,并以字符串形式返回响应 然后在C#应用程序中,有一个通过单击按钮调用的函数,该函数异步调用MakeReq

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

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

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

  • 然后在C#应用程序中,有一个通过单击按钮调用的函数,该函数异步调用MakeRequest()多次:

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

  • 在上面的示例中,MakeRequest()被调用了3次。当我监视Requests/sec性能计数器时,我在web服务器上看到的是,它收到2个请求,然后3秒后又收到1个请求。这是出于设计,因为System.Net.ServicePointManager.DefaultConnectionLimit的默认值是2,所以我的C#应用程序一次只能发送2个请求,尽管我要求3个。C#应用程序完成按钮点击的总时间为6秒

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

    接下来,我将C#应用程序更改为同时拨打60个电话,而不是3个。这就是事情变得有趣的地方。当我点击按钮时,我希望web服务器上的每秒请求数达到60,C#应用程序在3秒内完成按钮点击。我得到的是web服务器请求/秒,显示5个,3秒后再显示5个,等等,直到所有60个请求都已发出。当我再次单击按钮时,除了请求/秒峰值为10或15外,其他图片都是相同的,而且按钮单击显然完成得更快。再次单击-这次请求/秒显示两个峰值至30,按钮单击在6秒内完成。随后的按钮点击会导致每秒请求数先上升到40,然后上升到20(总共60个请求),然后上升到50和10,然后上升到55和5,最后我的C#app开始一次性发送所有60个请求。按钮点击在3秒内完成,web服务器上的Requests/sec显示一个峰值到60。如果我继续按下按钮,我总是同时收到所有60个请求

    但这还不是全部。如果我停止按下按钮,我的C#应用程序似乎“忘记”了以前的成就。我没有重新启动应用程序,只是停止按下按钮一分钟,在下一次按下时,我一次返回到5个请求,如果我继续按下按钮,上述场景将重复

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

    谁能解释一下发生了什么事?多谢各位


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

    <!-- 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();
        }
    }
    
    
    私有HttpClient _HttpClient=新HttpClient();
    私有异步无效按钮1\u单击(对象发送方,事件参数e)
    {
    ServicePointManager.DefaultConnectionLimit=1000000;
    var sw=Stopwatch.StartNew();
    var responses=wait Task.WhenAll(MakeRequest(),MakeRequest(),MakeRequest());
    sw.Stop();
    var msg=String.Join(“\r\n”,responses)+”\r\n\r\n运行时间:“+sw.elapsedmillyses;
    MessageBox.Show(msg);
    }
    专用异步任务MakeRequest()
    {
    使用(var message=await _httpClient.GetAsync(“http://TestServer/TestPage.aspx"))
    {
    返回wait message.Content.ReadAsStringAsync();
    }
    }
    
    两个原因:

  • 客户端Windows SKU将并发IIS请求数限制为10
  • 显然,您的客户机使用同步IO,或者正在阻塞。将线程池预热需要一段时间。线程只随时间注入。要么使用异步IO并保持非阻塞状态,要么确保您需要的线程实际存在。关于“遗忘”:空闲池线程会随着时间的推移而失效。因此,您的测试对时间非常敏感。非常不可靠,不要将其投入生产

  • 谢谢你的回复。1.是的,我遇到了这个问题,所以将网页移动到Win Server 2008上的IIS。事实上,我也试着在Server2008上运行发送请求的MVC页面——与从Win10运行的结果相同。2.不知道为什么我的客户端代码会被同步删除。我在原始问题中发布了代码。你能建议我如何修改它吗?代码很好。你能发布一次完成60个请求的代码吗?顺便说一句,ASP.NET线程池将因所有这些同步等待而过载。使用异步mvc操作并使用
    await Task.Delay
    。一次执行60个请求的代码与上面发布的代码相同,但行
    var responses=await Task.whalll(MakeRequest(),MakeRequest(),MakeRequest())中的代码除外重复
    MakeRequest()
    60次。关于ASP.Net线程池过载,我认为不会发生这种情况,因为当我的客户端应用程序最终同时发送60个请求时,web服务器会成功地同时处理所有请求。检查此处:,部分“为IIS 7.5/7.0集成模式配置ASP.NET 4 MaxConcurrentRequests”“当我的客户端应用程序最终发送时”“您如何知道它们在所有情况下都没有发送,但服务器处理它们的速度很慢?”?有许多性能计数器,有些是误导性的。使用一个异步mvc操作并使用wait Task.Delay,这样我们就可以消除我的猜测。好的,将服务器端更改为异步管道确实改变了一些事情。我把它改成:
    。现在,单击第一个按钮可以直接发送5个左右的请求,然后开始一次发送一个请求。在服务器上,每秒请求数首先显示一个小峰值,