检索Task.WhenAll抛出异常时的工作

时间:2015-03-12 00:54:41

标签: c# asynchronous

考虑

string[] pages;
Task [] asyncOps = 
    (from url in urls select DownloadStringAsync(url)).ToArray();
try
{
    pages = await Task.WhenAll(asyncOps);
    ...
}
catch(Exception exc)
{
    foreach(Task<string> faulted in asyncOps.Where(t => t.IsFaulted))
    {
        … // work with faulted and faulted.Exception
    }
}
来自https://msdn.microsoft.com/en-us/library/hh873173%28v=vs.110%29.aspx

。如何检索DID有效的页面?

或者更好的是,我如何继续计算其余页面?

3 个答案:

答案 0 :(得分:4)

不是单独进行所有下载,然后单独处理每个成功/错误,我认为如果你定义一个单独的下载和处理错误,它会更清晰。操作:

Task [] asyncOps = 
    (from url in urls select DownloadStringWithErrorCheckingAsync(url)).ToArray();
string[] pages = await Task.WhenAll(asyncOps);
var successfulPages = pages.Where(x => x != null);

...

private static Task<string> DownloadStringWithErrorCheckingAsync(string url)
{
  try
  {
    return await DownloadStringAsync(url);
  }
  catch(Exception exc)
  {
    ... // work with exc
    return null;
  }
}

答案 1 :(得分:1)

我也有同样的问题。我需要启动几个任务,等待每个任务终止,然后处理所有任务Status / Exception / Result。

我不能使用斯蒂芬的解决方案,因为最终的处理并不是彼此独立的。它是某种形式:如果task1为Ok,我将尝试获取task2的结果,如果没有,我将获取task3结果。我需要每个回答来推断我的行为。

public static Task WhenAllNoThrow(this Task[] toWait, CancellationToken token)
{
    return TaskEx.WhenAll(toWait).ContinueWith((t) => { t?.Exception?.Handle((exc) => true); }, token);
}

我不等待WhenAll的结果,而是ContinueWith的结果,其行为只能默默地处理异常。

它不是很优雅,但我们可以用这样的方法隐藏它:

[Inject] public InputController       inputController { private get; set; }
[Inject] public ICommandFactory       commandFactory  { private get; set; }
[Inject] public NetworkMachineManager machineManager  { private get; set; }

编辑:添加了空条件运算符?。

答案 2 :(得分:0)

不清楚是什么&#34; DownloadStringAsync&#34;是的,我以为它是WebClient.DownloadStringAsync

此函数不返回任务,您需要订阅complete事件以捕获结果。

它似乎不是你想要做的,所以我改变你的代码来做一个并行for循环。

Dictionary<string, string> pages = new Dictionary<string, string>();
Dictionary<string, string> errors = new Dictionary<string, string>();
string[] urls = new string[] { "http://www.google.com", "http://www.bbc.co.uk" };

Parallel.ForEach<string>(urls, (url) =>
{
    var webClient = new System.Net.WebClient();

    try
    {
        pages[url] = webClient.DownloadString(new Uri(url));
    }
    catch(Exception ex)
    {
        errors[url] = ex.Message;
    }                
});

// The successful
foreach(var kvp in pages)
{
    Console.WriteLine(kvp.Key);
    //Console.WriteLine(kvp.Value);
}

// The failures
foreach (var kvp in errors)
{
    Console.WriteLine(kvp.Key);
    //Console.WriteLine(kvp.Value);
}