C# System.Threading.Tasks-无法使用Task.WaitAll()捕获异常
我试图并行运行一些任务,每个任务都返回一个值。一旦它们全部完成,我想利用这些返回的结果。我遇到的问题是,如果某个任务抛出异常,则捕获该异常 根据我在其他一些SO问题上看到的内容,我认为下面的简化代码应该可以工作。但是,当我在VisualStudio中运行它时,我的异常不会得到处理C# System.Threading.Tasks-无法使用Task.WaitAll()捕获异常,c#,C#,我试图并行运行一些任务,每个任务都返回一个值。一旦它们全部完成,我想利用这些返回的结果。我遇到的问题是,如果某个任务抛出异常,则捕获该异常 根据我在其他一些SO问题上看到的内容,我认为下面的简化代码应该可以工作。但是,当我在VisualStudio中运行它时,我的异常不会得到处理 using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Threading;
class Program
{
static void Main()
{
int[] ids = { 1, 2, 3, 4 };
Test t = new Test();
t.Process(ids);
}
}
class Test
{
public void Process(int[] ids)
{
var tasks = new List<Task<Tuple<int, bool>>>(ids.Count());
foreach (int id in ids)
{
//The task will run at an indeterminate time so create a copy of id as it may have a new value assigned before that occurs
int i = id;
var task = Task.Factory.StartNew(() => DoWork(i));
tasks.Add(task);
}
try
{
Task.WaitAll(tasks.ToArray());
}
catch (AggregateException ex)
{
foreach (var innerEx in ex.InnerExceptions)
{
Console.WriteLine(innerEx);
}
}
foreach (var t in tasks)
{
Tuple<int, bool> result = t.Result;
Console.WriteLine(string.Format("{0} - success = {1}", result.Item1, result.Item2));
}
}
private Tuple<int, bool> DoWork(int i)
{
Console.WriteLine(string.Format("Processing {0}", i));
Thread.Sleep(i * 500);
if (i == 3)
{
//This exception does not get caught.
throw new Exception(string.Format("exception thrown on: {0}", i));
}
return new Tuple<int, bool>(i, true);
}
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用System.Threading.Tasks;
使用系统线程;
班级计划
{
静态void Main()
{
int[]id={1,2,3,4};
测试t=新测试();
t、 进程(ids);
}
}
课堂测试
{
公共无效进程(int[]id)
{
var tasks=新列表(ids.Count());
foreach(id中的int-id)
{
//任务将在不确定的时间运行,因此创建id的副本,因为在此之前可能已为其分配了新值
int i=id;
var task=task.Factory.StartNew(()=>DoWork(i));
任务。添加(任务);
}
尝试
{
Task.WaitAll(tasks.ToArray());
}
捕获(聚合异常)
{
foreach(ex.InnerExceptions中的var innerEx)
{
控制台写入线(innerEx);
}
}
foreach(任务中的var t)
{
Tuple result=t.result;
WriteLine(string.Format(“{0}-success={1}”,result.Item1,result.Item2));
}
}
私有元组DoWork(int i)
{
WriteLine(string.Format(“处理{0}”,i));
睡眠(i*500);
如果(i==3)
{
//此异常不会被捕获。
抛出新异常(string.Format(“在{0}上抛出的异常”,i));
}
返回新的元组(i,true);
}
}
我所期望的应该打印出来(由于并行运行,订单可能会更改):
处理1处理2
处理3
处理4
异常引发:3
1-成功=正确
2-成功=正确
4-成功=正确
我是否完全误解了Task.WaitAll的工作原理?不,你不是。但是,您将观察异常两次。Task.WaitAll将引发异常,您的代码将输出有关异常的信息。然后,当您从t.result(任务仍然包含引发异常的任务)获取该任务的结果时,您将再次获得异常 要解决此问题,您至少有两种选择:
公共作废流程(int[]id)
{
var tasks=新列表(ids.Count());
foreach(id中的int-id)
{
//任务将在不确定的时间运行,因此创建id的副本,因为在此之前可能已为其分配了新值
int i=id;
var task=task.Factory.StartNew(()=>DoWork(i));
任务。添加(任务);
}
foreach(任务中的var t)
{
尝试
{
Tuple result=t.result;
WriteLine(string.Format(“{0}-success={1}”,result.Item1,result.Item2));
}
捕获(聚合异常)
{
foreach(ex.InnerExceptions中的var innerEx)
{
Console.WriteLine(innerEx.Message);
}
}
}
}
是-如果要停止正在运行的任务,则需要执行取消,否则它们将如何在“良好状态”下停止?不要对控制流使用异常。检查Task.Exception。如果你知道结果会丢,就不要让它丢。不过,+1.小心处理Task.Exception。它只报告已经发生的异常——它不是阻塞调用。在访问t.Result之前添加t.Exception为null的检查不会改变示例中程序的行为。WaitAll将等待所有操作,但我忽略了您的代码没有使用它。那你是对的。
public void Process(int[] ids)
{
var tasks = new List<Task<Tuple<int, bool>>>(ids.Count());
foreach (int id in ids)
{
//The task will run at an indeterminate time so create a copy of id as it may have a new value assigned before that occurs
int i = id;
var task = Task.Factory.StartNew(() => DoWork(i));
tasks.Add(task);
}
foreach (var t in tasks)
{
try
{
Tuple<int, bool> result = t.Result;
Console.WriteLine(string.Format("{0} - success = {1}", result.Item1, result.Item2));
}
catch (AggregateException ex)
{
foreach (var innerEx in ex.InnerExceptions)
{
Console.WriteLine(innerEx.Message);
}
}
}
}