C# HTTP客户端在线程并行池中获取请求-随机故障
我有一个API,它提供了一些传感器的状态(位于Azure函数上) 我的客户端应用程序需要每秒钟检查一次每个传感器!因此,在本例中,我有10个传感器,客户端需要每秒发送10个http get请求 我决定使用Parallel来实现这一点,并从我的方法的每个实例中创建一个池,该方法运行一个执行Get请求的实例 这是一个主要的方法,它协调并将每个传感器添加到池中,并调用它们C# HTTP客户端在线程并行池中获取请求-随机故障,c#,console-application,httpclient,.net-5,C#,Console Application,Httpclient,.net 5,我有一个API,它提供了一些传感器的状态(位于Azure函数上) 我的客户端应用程序需要每秒钟检查一次每个传感器!因此,在本例中,我有10个传感器,客户端需要每秒发送10个http get请求 我决定使用Parallel来实现这一点,并从我的方法的每个实例中创建一个池,该方法运行一个执行Get请求的实例 这是一个主要的方法,它协调并将每个传感器添加到池中,并调用它们 public override Task Run(List<int> sensors)
public override Task Run(List<int> sensors)
{
try
{
List<Action> actions = new List<Action>();
foreach (var prd in sensors)
{
actions.Add(async () => await Process(prd));
}
ParallelOptions parallelOptions = new ParallelOptions
{
MaxDegreeOfParallelism = 20
};
Parallel.Invoke(parallelOptions, actions.ToArray());
}
catch (Exception ex)
{
Run(sensors);
}
return Task.CompletedTask;
}
我知道它在我的GetAsync方法中,但我不明白为什么它在运行几分钟后发生,而不仅仅是从一开始
还请注意,我必须通过调用使我的GetAsync方法不异步。结果就像我在等待一样,然后应用程序在启动第一个请求之前崩溃!似乎它不喜欢在并行池中被调用
谢谢你的帮助
更新了更多详细信息:
HttpClientService.cs
public class HttpClientService : IHttpClientService
{
private readonly HttpClient _client;
private readonly ILogger<HttpClientService> _logger;
private static readonly JsonSerializerSettings JsonSerializerSettings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore };
public HttpClientService(HttpClient client, ILogger<HttpClientService> logger)
{
_client = client;
_logger = logger;
}
.
.
.
公共类HttpClientService:IHttpClientService
{
私有只读HttpClient\u客户端;
专用只读ILogger\u记录器;
私有静态只读JsonSerializerSettings JsonSerializerSettings=new JsonSerializerSettings{NullValueHandling=NullValueHandling.Ignore};
公共HttpClientService(HttpClient客户端,ILogger记录器)
{
_客户=客户;
_记录器=记录器;
}
.
.
.
这就是我注册HttpClient的方式
services.AddHttpClient<IHttpClientService, HttpClientService>();
services.AddHttpClient();
以下是一些一般准则:
async
lambdas添加为Action
委托,其结果是async void
async
code。特别是,不要使用.Result
Parallel
不会与async
混用,因为Parallel
用于CPU绑定的多线程并行,而不是I/O绑定的无线程异步。您需要的解决方案是异步并发,即Task.whalll
public override async Task Run(List<int> sensors)
{
var tasks = sensors
.Select(prd => Process(prd))
.ToList();
await Task.WhenAll(tasks);
}
private async Task<string> Process(int sensorId)
{
while (true)
{
await Task.Delay(1000);
try
{
SensorModel response = await _httpClientService.GetAsync<SensorModel>(string.Format(apiUrl, sensorId));
if (response != null)
{
if (response.Status == "success")
{
...
}
_logger.LogError($"API connection unsuccesful...");
return null;
}
_logger.LogError($"API connection failed...");
return null;
}
catch (Exception ex)
{
_logger.LogError($"Exception in retrieving sensor data {StringExtensions.GetCurrentMethod()} {ex}");
return null;
}
}
}
公共覆盖异步任务运行(列出传感器)
{
var任务=传感器
.选择(prd=>过程(prd))
.ToList();
等待任务。何时(任务);
}
专用异步任务进程(int-sensorId)
{
while(true)
{
等待任务。延迟(1000);
尝试
{
SensorModel response=wait_httpClientService.GetAsync(string.Format(apirl,sensorId));
if(响应!=null)
{
如果(response.Status==“success”)
{
...
}
_logger.LogError($“API连接未成功…”);
返回null;
}
_logger.LogError($“API连接失败…”);
返回null;
}
捕获(例外情况除外)
{
_logger.LogError($“检索传感器数据时发生异常{StringExtensions.GetCurrentMethod()}{ex}”);
返回null;
}
}
}
如何将HttpClient注入您的HttpClientService?如何将您的服务添加到DI?请更新您的问题完成,感谢@saeedesmaeelinejaddin而不是使用线程。睡眠(1000);
使用此等待任务。延迟(1000)
然后测试它的安全性,现在就去尝试它不起作用,它经历了一个循环,然后就存在了,我认为这是因为在延迟之后它返回一个任务,当Run方法得到一个任务时,它假设应用程序已经完成了执行!非常感谢,我没有意识到异步无效!它现在正在按预期工作!
public class HttpClientService : IHttpClientService
{
private readonly HttpClient _client;
private readonly ILogger<HttpClientService> _logger;
private static readonly JsonSerializerSettings JsonSerializerSettings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore };
public HttpClientService(HttpClient client, ILogger<HttpClientService> logger)
{
_client = client;
_logger = logger;
}
.
.
.
services.AddHttpClient<IHttpClientService, HttpClientService>();
public override async Task Run(List<int> sensors)
{
var tasks = sensors
.Select(prd => Process(prd))
.ToList();
await Task.WhenAll(tasks);
}
private async Task<string> Process(int sensorId)
{
while (true)
{
await Task.Delay(1000);
try
{
SensorModel response = await _httpClientService.GetAsync<SensorModel>(string.Format(apiUrl, sensorId));
if (response != null)
{
if (response.Status == "success")
{
...
}
_logger.LogError($"API connection unsuccesful...");
return null;
}
_logger.LogError($"API connection failed...");
return null;
}
catch (Exception ex)
{
_logger.LogError($"Exception in retrieving sensor data {StringExtensions.GetCurrentMethod()} {ex}");
return null;
}
}
}