.net 任务并行库和异常?

.net 任务并行库和异常?,.net,task-parallel-library,.net,Task Parallel Library,我应该这样做吗 int x = 0; Task<int> calc = Task.Factory.StartNew (() => 7 / x); try { Console.WriteLine (calc.Result); } catch (AggregateException aex) { Console.Write (aex.InnerException.Message); // Attempted to divide by 0 } intx=0; 任务计算=T

我应该这样做吗

int x = 0;
Task<int> calc = Task.Factory.StartNew (() => 7 / x);
try
{
  Console.WriteLine (calc.Result);
}
catch (AggregateException aex)
{
  Console.Write (aex.InnerException.Message);  // Attempted to divide by 0
}
intx=0;
任务计算=Task.Factory.StartNew(()=>7/x);
尝试
{
Console.WriteLine(计算结果);
}
捕获(聚合异常aex)
{
Console.Write(aex.InnerException.Message);//试图除以0
}
还是这个

int x = 0;
try
{
  Task<int> calc = Task.Factory.StartNew (() => 7 / x);
  Console.WriteLine (calc.Result);
}
catch (AggregateException aex)
{
  Console.Write (aex.InnerException.Message);  // Attempted to divide by 0
}
intx=0;
尝试
{
任务计算=Task.Factory.StartNew(()=>7/x);
Console.WriteLine(计算结果);
}
捕获(聚合异常aex)
{
Console.Write(aex.InnerException.Message);//试图除以0
}

如果任务在我们进入try-catch块之前立即启动,那么我们将无法捕获它

使用
任务
的一个要点是,你基本上不必担心这样的事情

正如您所注意到的,第一个示例中有两种可能的事件顺序:

  • StartNew()
    是从线程A调用的
  • Result
    getter是从线程A调用的。任务尚未完成,因此调用被阻塞
  • 委托在线程池线程B上执行,并抛出
    dividebyzeroception
  • 线程A唤醒并
    结果
    抛出
    聚合异常
  • 第二种可能性是:

  • StartNew()
    是从线程A调用的
  • 委托在线程池线程B上执行,并抛出
    dividebyzeroception
  • Result
    getter是从线程A调用的。任务已经完成,因此调用会立即抛出
    aggregateeexception
  • 如您所见,在这两种情况下,
    Result
    getter都会抛出异常,代码执行的顺序并不重要

    只有当
    StartNew()
    能够抛出
    aggregateeexception
    时,您的第二个版本才有意义,但这永远不会发生


    让我重复一遍:TPL负责所有的同步,您不必在这里担心。

    使用
    任务的一个要点是,您基本上不必担心类似的事情

    正如您所注意到的,第一个示例中有两种可能的事件顺序:

  • StartNew()
    是从线程A调用的
  • Result
    getter是从线程A调用的。任务尚未完成,因此调用被阻塞
  • 委托在线程池线程B上执行,并抛出
    dividebyzeroception
  • 线程A唤醒并
    结果
    抛出
    聚合异常
  • 第二种可能性是:

  • StartNew()
    是从线程A调用的
  • 委托在线程池线程B上执行,并抛出
    dividebyzeroception
  • Result
    getter是从线程A调用的。任务已经完成,因此调用会立即抛出
    aggregateeexception
  • 如您所见,在这两种情况下,
    Result
    getter都会抛出异常,代码执行的顺序并不重要

    只有当
    StartNew()
    能够抛出
    aggregateeexception
    时,您的第二个版本才有意义,但这永远不会发生


    让我重复一遍:TPL负责所有的同步,您不必在这里担心它。

    任务有一个
    异常
    属性,它保存在任务执行过程中抛出的异常(如果有)。这意味着您可以执行以下操作:

    int x = 0;
    Task<int> calc = Task.Factory.StartNew(() => 7 / x);
    calc.ContinueWith(t => Console.WriteLine ("Got exception of {0}", t.Exception),
                      TaskContinuationOptions.OnlyOnFaulted);
    
    intx=0;
    任务计算=Task.Factory.StartNew(()=>7/x);
    calc.ContinueWith(t=>Console.WriteLine(“获取了{0}的异常”,t.exception),
    TaskContinuationOptions.OnlyOnFaulted);
    
    任务有一个
    异常
    属性,该属性保存在任务执行期间引发的异常(如果有)。这意味着您可以执行以下操作:

    int x = 0;
    Task<int> calc = Task.Factory.StartNew(() => 7 / x);
    calc.ContinueWith(t => Console.WriteLine ("Got exception of {0}", t.Exception),
                      TaskContinuationOptions.OnlyOnFaulted);
    
    intx=0;
    任务计算=Task.Factory.StartNew(()=>7/x);
    calc.ContinueWith(t=>Console.WriteLine(“获取了{0}的异常”,t.exception),
    TaskContinuationOptions.OnlyOnFaulted);
    
    您希望在try块中执行尽可能少的代码,因为包含的代码越多,您将捕获到的错误和不必要的异常就越多。你只想抓住那些你知道它们是良性的。你不想吞下虫子

    因此,要么这样做:

    var task = ...;
    int result;
    try { result = task.Result; } //just catch task.Result
    ...
    
    甚至这个:

    if (task.Exception != null) { /* error */ }
    else { /* use task.Result */ }
    

    您希望在try块中执行尽可能少的代码,因为包含的代码越多,您将捕获到的错误和不需要的异常就越多。你只想抓住那些你知道它们是良性的。你不想吞下虫子

    因此,要么这样做:

    var task = ...;
    int result;
    try { result = task.Result; } //just catch task.Result
    ...
    
    甚至这个:

    if (task.Exception != null) { /* error */ }
    else { /* use task.Result */ }
    

    在这种情况下,不需要将其包含在try块中。将不会引发异常,除非向其传递要执行的null操作。正在运行的操作引发的任何异常都将传播到任务中,而不是堆栈中


    更一般地说,我认为这类情况的经验法则是,异常应该始终进入任务。例如,如果在异步方法中第一次等待之前抛出异常,它也会进入结果任务,而不是向上传播堆栈。

    在这种情况下,您不需要将其包括在try块中。将不会引发异常,除非向其传递要执行的null操作。正在运行的操作引发的任何异常都将传播到任务中,而不是堆栈中


    更一般地说,我认为这类情况的经验法则是,异常应该始终进入任务。例如,如果在异步方法中第一次等待之前抛出异常,它也会进入结果任务,而不是向堆栈上传播。

    执行
    try{result=task.result;}
    将阻止执行任务的线程,这可能不是他想要的。不确定他的意图。他的问题与那个问题是正交的,所以我忽略了它。我直截了当地回答他的问题。做
    try{result=