[英]C# Async/Parallel Programming with Cancellation Tokens
我有一個實現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
和o.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;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.