使用长时间运行的后台消费者任务时,Task.Factory.StartNew中的静默exception?

这通知未处理的exception:

new Thread(_ => { throw new Exception(); }).Start(); 

这没有(至少在你等待/检索结果之前):

 Task.Factory.StartNew(() => { throw new Exception(); }); 

为什么? 发生exception的线程发生了什么? 它死了吗?

这是一个运行任务但不需要其结果或需要等待它的问题,如下所示:

 _operationQueue = new BlockingCollection(); Task.Factory.StartNew(() => { foreach (var item in _operationQueue.GetConsumingEnumerable()) { // do something that throws } }, TaskCreationOptions.LongRunning); 

在这种情况下, _operationQueue处于什么状态?

我知道我可以使用Continition with TaskContinuationOptions.OnlyOnFaulted,你能继续处理吗?

那么,你认为应该发生什么呢? 您是否认为每当在另一个线程中抛出exception时,它应该立即传播到启动该任务的线程? 我非常不同意。 首先,调用线程中的代码将被强制中止它在中间的操作,这很可能会导致严重的问题。 只需查看围绕Thread.Abort所有post,看看当你允许在程序执行中的某个任意点而不是某些已知点抛出exception时出现的所有非常重要的问题。

如果您建议整个程序在任务代码抛出exception时崩溃,那么我会说这一点根本不可取。 在极少数情况下,如果任务出现故障,您可以(相当容易)在任务上创建一个延续整个过程的延续。 我自己还不需要自己创造这样的延续。 如果系统设计为在任务抛出exception时关闭进程,那么获得相反的行为就不那么容易了。

发生exception的线程发生了什么? 它死了吗?

如果捕获到exception,则在catch之后继续执行; 如果它传播通过整个调用堆栈,那么exception将由Task框架内的代码捕获,该代码包装exception并使其可用于continuation。

在这种情况下,_operationQueue处于什么状态?

这是一个完美的队列,已经从中移除了1..N个项目。 如果循环的主体总是抛出,那么将从中取出一个项目。 如果它只是有时会抛出,那么将从中取出一些物品。 其余项目仍在队列中,可以被任何其他有权访问的线程删除。 如果队列不再可访问,那么它将有资格进行垃圾回收。

我知道我可以使用Continition with TaskContinuationOptions.OnlyOnFaulted,你能继续处理吗?

调用线程可以; 当然。 任务本身只能通过在其委托中使用try/catch来继续。 如果exception被抛出到任务出错的程度,那么任何事都不会允许该任务继续执行。

任务中的exception由TaskScheduler捕获。 如果您不想观察任务的结果,但希望收到有关任务中未处理的exception的通知,则会发生TaskScheduler.UnobservedTaskException事件。 请注意,此事件不会立即触发,但在完成Task如果从未检索到exception。 在.Net 4中,重新抛出了未观察到的任务exception,并成为结束该过程的未处理exception,但在.Net 4.5中进行了更改。