c# - 使用取消标记的 C# 异步/并行编程
问题描述
IService
我有一个实现接口的服务列表。我还有一个实现ICalculator
接口的计算服务。
服务
public interface IService
{
Task<List<Response>> GetSomeDataAsync(CancellationToken cancellationToken = default);
}
计算器
public interface ICalculator
{
Task<List<Response>> CalculateAsync(Request request, CancellationToken cancellationToken = default);
}
我希望所有实现的服务并行IService
运行,并在每个服务的结果上运行。IService.GetSomeDataAsync()
ICalculator.CalculateAsync()
public async Task<List<Response>> Run()
{
var tokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(10));
var data = await Task.WhenAll(_services.Select(service =>
{
var results = service.GetSomeDataAsync(tokenSource.Token);
var newResults = results.ContinueWith(x =>
{
var request = new request
{
Data = x.Result
};
return _calculator.CalculateAsync(request, tokenSource.Token);
}, tokenSource.Token);
return newResults;
}));
var response = data.SelectMany(o => o.Result)
.ToList();
return response;
}
这一切都按预期工作。调用x.Result
ando.Result
不会锁定线程,因为任务在调用时已完成。当我尝试实现取消令牌时,问题就出现了。我希望能够Iservice.GetSomeDataAsync()
在需要很长时间时取消。我也不言而喻,如果IService.GetSomeDataAsync()
被取消,那么ICalculator.CalculateAsync()
也不应该运行。
我设置CancellationTokenSource
为在 10 秒内取消。这可行,但它抛出了我认为的错误,OperationCanceledException
但我无法继续执行该程序或捕获错误。
该IService.GetSomeDataAsync()
方法看起来像这样。
public async Task<List<Response>> GetSomeDataAsync(CancellationToken cancellationToken)
{
try
{
var result = await "http://slowwly.robertomurray.co.uk/delay/100000/url/http://www.google.co.uk"
.GetStringAsync(cancellationToken);
}
catch (OperationCanceledException x)
{
Console.WriteLine(x);
}
return result;
}
*请注意,我使用 Flurl 进行 Web 请求。我将 传递
tokenSource.Token
给通过包含方法参数传入的方法。
该ICalculator.CalculateAsync()
方法看起来像这样。
public async Task<List<Response>> CalculateAsync(Request request, CancellationToken cancellationToken = default)
{
try
{
var result = await "http://slowwly.robertomurray.co.uk/delay/2000/url/http://www.google.co.uk"
.GetStringAsync(cancellationToken);
}
catch (OperationCanceledException x)
{
Console.WriteLine(x);
}
return result;
}
*请注意,我使用 Flurl 进行 Web 请求。我将 传递
tokenSource.Token
给通过包含方法参数传入的方法。
所以问题是我如何正确使用取消令牌来达到预期的结果?
解决方案
这个解决方案对我有用。
public async Task<List<Response>> Run()
{
var data = await Task.WhenAll(_services.Select(async service =>
{
var tokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(10));
try
{
results = await service.GetSomeDataAsync(tokenSource.Token);
}
catch (Exception x)
{
return new List<Response>();
}
var request = new Request
{
Data = results
};
try
{
return await _calculator.CalculateAsync(request, tokenSource.Token);
}
catch (Exception x)
{
return new List<Response>();
}
}));
var response = data
.SelectMany(responses => responses)
.ToList();
return response;
}
推荐阅读
- c# - 多项式插值牛顿法
- javascript - Vue.js如何从表单中添加的数组中保存缓存元素
- c# - DocumentFormat.OpenXml Nuget 包有许多依赖项,如 Microsoft.NetCore.Platforms
- javascript - JavaScript style.background-color
- linux - 在 Perl 中连接数千个文件的最有效方法
- java - 为单个 java Servlet 添加多个表单
- c++ - C++ 在循环中捕获异常并在循环结束后重新抛出?
- javascript - Javascript irc bot node.js从文本文件错误中连接字符串
- debugging - 为什么在 org-mode 中所有元键都未绑定?
- javascript - 从数组中某些位置的输入中推送值