我正在更新我的并发技能。我的问题似乎相当普遍:从多个 Uris 读取、解析和处理结果等。我有 Concurrency in C# Cookbook .有几个使用 GetStringAsync 的示例,例如
static async Task<string> DownloadAllAsync(IEnumerable<string> urls)
{
var httpClient = new HttpClient();
var downloads = urls.Select(url => httpClient.GetStringAsync(url));
Task<string>[] downloadTasks = downloads.ToArray();
string[] htmlPages = await Task.WhenAll(downloadTasks);
return string.Concat(htmlPages);
}
我需要的是用于运行多个异步任务、捕获全部或部分成功的异步模式。
- url 1 成功
- url 2 成功
- Url 3 失败(超时、错误的 Uri 格式、401 等)
- url 4 成功
- ... 20 多个成功与否
如果任何失败,等待 DownloadAllAsync 任务将抛出一个聚合异常,丢弃累积的结果。根据我有限的研究,WhenAll 或 WaitAll 的行为相同。我想捕获异常,记录失败,但继续执行剩余的任务,即使它们都失败了。 我可以一个一个地处理它们,但这不是违背了让TPL管理整个过程的目的吗?是否有指向以纯 TPL 方式实现此目的的模式的链接?也许我使用了错误的工具?
最佳答案
I want to catch the exceptions, log the failures, but continue with the remaining tasks, even if they all fail.
在这种情况下,最简洁的解决方案是更改代码对每个元素的作用。即,当前代码:
var downloads = urls.Select(url => httpClient.GetStringAsync(url));
说“对于每个 url,下载一个字符串”。你想要它说的是“对于每个 url,下载一个字符串,然后记录并忽略任何错误”:
static async Task<string> DownloadAllAsync(IEnumerable<string> urls)
{
var httpClient = new HttpClient();
var downloads = urls.Select(url => TryDownloadAsync(httpClient, url));
Task<string>[] downloadTasks = downloads.ToArray();
string[] htmlPages = await Task.WhenAll(downloadTasks);
return string.Concat(htmlPages);
}
static async Task<string> TryDownloadAsync(HttpClient client, string url)
{
try
{
return await client.GetStringAsync(url);
}
catch (Exception ex)
{
Log(ex);
return string.Empty; // or whatever you prefer
}
}
关于c# - 如何运行多个任务,处理异常并仍然返回结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27041797/