我试图找出在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();
答案 0 :(得分:1)
引发的行不在您的try catch中。
tasks.Add(Task.Run(() => Bar.MightThrowException(i)));
那将是抛出的内容。编辑:Task.Run立即排队,并可能立即运行任务。您的MightThrowException方法应该返回一个Task。然后,您可以将该任务添加到列表中,然后它将按您期望的那样在try catch中运行。有关其他信息,我发现本文非常有帮助
答案 1 :(得分:1)
您正在获取任务的结果,如果任务出错,则将其抛出异常,然后将其从列表中删除,这与链接中的代码会在之后等待从列表中将其删除。这样可以确保即使出现故障也可以将其从任务列表中删除。
还请注意,如果仅使用SemaphoreSlim
而不是具有诸如此类的任务列表,则整个过程会更加清晰明了。信号量是更少的代码,更清晰的代码,更容易修改的代码等。