使用WhenAny处理每个任务的异常

时间:2018-10-19 14:00:47

标签: c#

我试图找出在Task的{​​{3}}中实现多个任务时,如何正确处理由一个“坏” WhenAny引发的异常。

不幸的是,我一直为所有“好”任务引发异常,该异常在一个“坏”任务引发异常后完成。

我尝试添加ContinueWith来尝试获取剩余的“好”任务以返回正确的值。但是,即使“好”任务继续坚持,仍然会引发异常。

我该如何编码以确保一个“坏”任务已处理了其异常,同时又从其他“好”任务中获取了正确的值?

这是一个简化的示例来说明问题。

这模拟了抛出异常或返回良好结果的代码。在这种情况下,仅当输入为int 2时,它才会引发异常:

static class Bar {
    public static string MightThrowException(int i) {
        if (i == 2) throw new Exception("bad error: " + i.ToString());
        // if not 2, just return input
        return i.ToString();
    }
}

...这是应该处理该实例异常的代码:

public async Task<string> TestThrottle() {
    var tasks = new List<Task<string>>();
    var results = new List<string>();

    // mock the 'priming' that occurs in a throttling pattern
    tasks.Add(Task.Run(() => Bar.MightThrowException(0)));

    // begin throttling, for an additional 4 tasks
    for (var i = 1; i < 5; i++) {
        try {
            var task = await Task.WhenAny(tasks);
            results.Add(task.Result);
            tasks.Remove(task);
        }
        catch (Exception ex) {
            results.Add("handled " + ex.Message);
        }
        tasks.Add(Task.Run(() => Bar.MightThrowException(i)));
    }

    return string.Join("\n", results);
}

以这种方式在Main()中触发整个事件:

Task.Run(() => {
    string result = new Foo().TestThrottle().Result;
    System.Diagnostics.Debug.WriteLine(result);
}).Wait();

2 个答案:

答案 0 :(得分:1)

引发的行不在您的try catch中。

tasks.Add(Task.Run(() => Bar.MightThrowException(i)));

那将是抛出的内容。编辑:Task.Run立即排队,并可能立即运行任务。您的MightThrowException方法应该返回一个Task。然后,您可以将该任务添加到列表中,然后它将按您期望的那样在try catch中运行。有关其他信息,我发现本文非常有帮助

https://msdn.microsoft.com/en-us/magazine/jj991977.aspx

答案 1 :(得分:1)

您正在获取任务的结果,如果任务出错,则将其抛出异常,然后将其从列表中删除,这与链接中的代码会在之后等待从列表中将其删除。这样可以确保即使出现故障也可以将其从任务列表中删除。

还请注意,如果仅使用SemaphoreSlim而不是具有诸如此类的任务列表,则整个过程会更加清晰明了。信号量是更少的代码,更清晰的代码,更容易修改的代码等。