C# 异步和并行HttpClient请求到62000+;机器:最佳实践请求
我有这个场景,我正在研究需要将通知消息发送到公司所有工作站的位置。我们有一个处理桌面通知的客户端服务,它是一个非常简单的WebApi 问题/要求 如何从server/ASP.Net web app异步和并行地向所有这些计算机发送请求,并捕获其对自定义日志文件的响应 许多机器可能在发出通知时关闭,或者dns可能无法解析,因为机器可能已停用 当前原型化代码的请求/响应周期需要为非阻塞周期。这样用户就不必等待所有这些机器的响应 我的作业: 我知道异步操作更适合于IO绑定的操作,但是机器的数量太多,让我感觉并行和异步 加在一起,可能更适合这种情况 我已将ServicePointManager.DefaultConnectionLimit设置为10000 已传递构造函数的HttpClient,其dispose选项为false。请参阅下面的代码-工厂类 框架中的HttpClient类是为重用而设计的,但据我所知,某些属性不能像基址那样更改。资料来源: 我使用特定于请求/响应的ID(关联ID)来确保给定请求的所有异步和并行操作都位于同一文件夹中 TaskCanceledException捕获块永远不会被命中 超时时间已经延长到30秒,我确信这已经足够了 原型代码:C# 异步和并行HttpClient请求到62000+;机器:最佳实践请求,c#,asp.net,asp.net-web-api,httpclient,dotnet-httpclient,C#,Asp.net,Asp.net Web Api,Httpclient,Dotnet Httpclient,我有这个场景,我正在研究需要将通知消息发送到公司所有工作站的位置。我们有一个处理桌面通知的客户端服务,它是一个非常简单的WebApi 问题/要求 如何从server/ASP.Net web app异步和并行地向所有这些计算机发送请求,并捕获其对自定义日志文件的响应 许多机器可能在发出通知时关闭,或者dns可能无法解析,因为机器可能已停用 当前原型化代码的请求/响应周期需要为非阻塞周期。这样用户就不必等待所有这些机器的响应 我的作业: 我知道异步操作更适合于IO绑定的操作,但是机器的数量太多,让我
public class HttpClientFactory : IHttpClientFactory
{
public void CreateClient(string baseUrl, Action<HttpClient> methodToExecute)
{
using (var handler = new HttpClientHandler())
{
handler.AllowAutoRedirect = true;
using (var client = new HttpClient(handler, false))
{
client.BaseAddress = new Uri(baseUrl);
client.Timeout = TimeSpan.FromSeconds(30);
methodToExecute(client);
}
}
}
}
公共类HttpClientFactory:IHttpClient工厂
{
public void CreateClient(字符串baseUrl,操作方法执行)
{
使用(var handler=new-HttpClientHandler())
{
handler.AllowAutoRedirect=true;
使用(var client=newhttpclient(handler,false))
{
client.BaseAddress=新Uri(baseUrl);
client.Timeout=TimeSpan.FromSeconds(30);
方法执行(客户);
}
}
}
}
其中IHttpClientFactory为瞬态(IoC)
workstationUrls.ForEach(baseUrl=>
{
_httpClientFactory.CreateClient(baseUrl,异步(客户端)=>
{
等待client.PostAsync(资源URL、内容).ContinueWith(t=>
{
尝试
{
var响应=t.结果;
var workstationResponse=新的workstationResponse
{
StatusCode=(int)response.StatusCode,
Response=Response.Content.ReadAsStringAsync().Result
};
workstationResponse.IsSuccess
=workstationResponse.StatusCode>=200&&
workstationResponse.StatusCode首先,异步和并行并不是相互排斥的;区别在于您使用的构造,以及与“传统”并行不同的是,您没有为每个异步操作消耗/阻塞线程
并发执行异步操作并等待(异步)所有操作完成的最基本构造是Task.whalll
async Task SendMessageToWorkstationAsync(string url)
(可以很容易地从代码中派生实现。)
那么就这样称呼它:
await Task.WhenAll(workstationUrls.Select(SendMessageToWorkstationAsync));
其次,关于HttpClient
,如果因为设置BaseAddress
而没有重用单个实例,那么解决方案很简单:不要这样做。:)这不是必需的。跳过工厂类,只需创建一个共享的HttpClient
实例,并为每个请求提供完整的URI
最后,根据各种因素,您可能仍然会发现62000多个并发请求超出了系统的处理能力。如果是这种情况,您将希望限制并行性。我发现最好的方法是使用TPL数据流。有关如何做到这一点的详细信息,请参阅。首先,异步和并行并不是相互排斥的不同之处在于您使用的构造,以及与“传统”并行不同的是,每个异步操作不消耗/阻塞线程
并发执行异步操作并等待(异步)所有操作完成的最基本构造是Task.whalll
async Task SendMessageToWorkstationAsync(string url)
(可以很容易地从代码中派生实现。)
那么就这样称呼它:
await Task.WhenAll(workstationUrls.Select(SendMessageToWorkstationAsync));
其次,关于HttpClient
,如果因为设置BaseAddress
而没有重用单个实例,那么解决方案很简单:不要这样做。:)这不是必需的。跳过工厂类,只需创建一个共享的HttpClient
实例,并为每个请求提供完整的URI
最后,根据各种因素,您可能仍然会发现62000多个并发请求超出了系统的处理能力。如果是这种情况,您将希望限制并行性。我发现最好的方法是使用TPL数据流。有关如何做到这一点的详细信息,请参阅。从更改操作操作方法开始将xecute
发送到一个func,该func返回一个任务,以便您可以等待与HttpClient
正确交互的异步方法。这导致了已处理的异常。Thans Peter,让我试试看这是否有什么不同。从更改