async / await,TaskEx.WhenAll和exception

时间:2011-10-09 08:20:41

标签: c# async-await

这只是一个想象中的问题,我希望该解决方案能够在各种类似场景中提供帮助。假设我需要计算网页上所有外部资源的总大小(图像,脚本等)。我下载页面,提取所有SRC信息并将URL列表转换为下载任务:

async Task<int> GetTotalSize(Uri uri) {
  string[] urls = ... code to extract all external resources' URLs from given page ...

  var tasks = from url in urls.Distinct()
                select new WebClient().DownloadDataTaskAsync(new Uri(url));
  var files = await TaskEx.WhenAll(tasks);
  return files.Sum(file => file.Length);
}

现在,如果其中一个链接因任何原因无法访问,则整个TaskEx.WhenAll将被WebException中止。我需要的是忽略单个任务中的任何WebExceptions,并假设在这种情况下长度为0。有什么想法吗?

3 个答案:

答案 0 :(得分:5)

只需添加一个单独的(异步)方法即可获得单个网址的大小。然后加起来。

如,

static async Task<int> GetTotalSizeAsync(params string[] urls)
{
    if (urls == null)
        return 0;
    var tasks = urls.Select(GetSizeAsync);
    var sizes = await TaskEx.WhenAll(tasks);
    return sizes.Sum();
}

static async Task<int> GetSizeAsync(string url)
{
    try
    {
        var str = await new WebClient().DownloadStringTaskAsync(url);
        return str.Length;
    }
    catch (WebException)
    {
        return 0;
    }
}

答案 1 :(得分:3)

此解决方案允许异步和并行执行,Jeff目前接受的答案没有。

var tasks = from url in urls.Distinct()
            select new WebClient().DownloadDataTaskAsync(new Uri(url));

try
{
    await TaskEx.WhenAll(tasks);
}
catch(Exception)
{
}

var files = tasks
    .Where(f => !f.IsFaulted)
    .Select(f => f.Result);

return files.Sum(file => file.Length);

借鉴https://stackoverflow.com/a/15857555/1152054

答案 2 :(得分:0)

我认为你不能用上面的例子来避免聚合例外 - aggregateexception是有意义的,因为异常也可能是由非webexception引起的,例如取消。我认为正确的模式应该是使用try catch块优雅地处理异常,如果“file”没有异常总结它。里德有一篇很好的帖子解释了同样的http://reedcopsey.com/2010/07/19/parallelism-in-net-part-18-task-continuations-with-multiple-tasks/

希望有所帮助