c# - 如何运行多个任务,处理异常并仍然返回结果

标签 c# task-parallel-library

我正在更新我的并发技能。我的问题似乎相当普遍:从多个 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);
}

我需要的是用于运行多个异步任务、捕获全部或部分成功的异步模式。

  1. url 1 成功
  2. url 2 成功
  3. Url 3 失败(超时、错误的 Uri 格式、401 等)
  4. url 4 成功
  5. ... 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/

相关文章:

c# - 为什么 Window.ShowDialog 没有阻塞在 TaskScheduler 任务中?

c# - 在 .Net 4.0 中使用 poor mans async/await 构造实现异步超时

c# - 有人可以解释幕后发生的事情吗?

c# - 非阻塞和重复发生的生产者/消费者通知程序实现

c# - 如果文本不存在,如何在文本后添加字符串?

c# - 使用内置的 Exists 方法检查 Azure Blob 存储中是否存在容器和 blob

c# - 使用 Entity Framework 运行并行计数查询

c# - 应如何在 IHostedService 中使用取消标记?

c# - 如何以编程方式移动 Windows 任务栏(需要两个)

java - Java 和 C# 之间的不同 MD5