我遇到异常处理和并行任务的问题。
下面显示的代码启动2个任务并等待它们完成。我的问题是,如果任务抛出异常,则永远不会到达catch处理程序。
List<Task> tasks = new List<Task>();
try
{
tasks.Add(Task.Factory.StartNew(TaskMethod1));
tasks.Add(Task.Factory.StartNew(TaskMethod2));
var arr = tasks.ToArray();
Task.WaitAll(arr);
}
catch (AggregateException e)
{
// do something
}
但是,当我使用以下代码等待超时的任务时,会捕获异常。
while(!Task.WaitAll(arr,100));
我似乎遗漏了一些东西,因为WaitAll
的文档描述了我的第一次尝试是正确的。请帮助我理解它为什么不起作用。
答案 0 :(得分:25)
无法重现这一点 - 它适用于我:
using System;
using System.Threading;
using System.Threading.Tasks;
class Test
{
static void Main()
{
Task t1 = Task.Factory.StartNew(() => Thread.Sleep(1000));
Task t2 = Task.Factory.StartNew(() => {
Thread.Sleep(500);
throw new Exception("Oops");
});
try
{
Task.WaitAll(t1, t2);
Console.WriteLine("All done");
}
catch (AggregateException)
{
Console.WriteLine("Something went wrong");
}
}
}
就像我期望的那样打印出“出了问题”。
您的某个任务是否可能未完成? WaitAll
确实等待所有任务完成,即使有些任务已经失败。
答案 1 :(得分:11)
以下是我解决问题的方法,正如我对上述答案/问题的评论中提到的那样:
调用者捕获由屏障协调的任务引发的任何异常,并通过强制取消发出其他任务的信号:
CancellationTokenSource cancelSignal = new CancellationTokenSource();
try
{
// do work
List<Task> workerTasks = new List<Task>();
foreach (Worker w in someArray)
{
workerTasks.Add(w.DoAsyncWork(cancelSignal.Token);
}
while (!Task.WaitAll(workerTasks.ToArray(), 100, cancelSignal.Token)) ;
}
catch (Exception)
{
cancelSignal.Cancel();
throw;
}
答案 2 :(得分:0)
我试图为集合中的每个项目创建一个调用,结果如下:
var parent = Task.Factory.StartNew(() => {
foreach (var acct in AccountList)
{
var currAcctNo = acct.Number;
Task.Factory.StartNew(() =>
{
MyLocalList.AddRange(ProcessThisAccount(currAcctNo));
}, TaskCreationOptions.AttachedToParent);
Thread.Sleep(50);
}
});
我必须在每次添加子任务后添加Thread.Sleep,因为如果我没有,那么该过程将倾向于在下一次迭代时覆盖currAcctNo。我的列表中有3个或4个不同的帐号,当它们分别处理时,ProcessThisAccount呼叫将显示所有呼叫的最后一个帐号。一旦我进入睡眠状态,这个过程就会很好。