我正在尝试创建一个并行进程,该进程不会阻塞我的主线程,但是在出现异常的情况下仍然会记录错误。最初我有以下代码:
var task = Task.Run(
() => _db.addData());
task.ContinueWith(continuationTask =>
{
if (continuationTask.Exception != null)
{
_logger.LogError(continuationTask.Exception, "Failed to log mismatch");
}
},
_taskScheduler);
运行应用程序代码时,_taskScheduler
设置为TaskScheduler.Current
。
运行此命令时,它将正确并行执行代码,并且当数据库出现问题时,continuationTask.Exception
将包含相应的异常消息。
指定TaskScheduler
的全部目的是让我可以控制单元测试中的执行顺序。就目前而言,在单元测试中,原始任务和延续将分别使用不同的任务调度程序-TaskScheduler
和MockTaskScheduler
运行。 (为简洁起见,没有显示单元测试代码,但是MockTaskScheduler
只是一个自定义实现,允许我排队和执行任务)
由于Task.Run
并没有使用TaskScheduler
作为参数,因此我尝试将代码更改为
var task = Task.Factory.StartNew(
() => _db.addData(),
CancellationToken.None,
TaskCreationOptions.None,
_taskScheduler);
task.ContinueWith(continuationTask =>
{
if (continuationTask .Exception != null)
{
_logger.LogError(continuationTask.Exception, "Failed to log mismatch");
}
},
_taskScheduler);
这使我的测试非常完美,因为我现在可以控制每个任务的执行时间,因为它们使用相同的可注入_taskScheduler
。但是,在使用TaskScheduler.Current
运行应用程序代码时,continuationTask.Exception
始终为null,从而阻止我记录任何异常。
Task.Run
填充continuationTask.Exception
而Task.Factory.StartNew
没有填充原因吗?我想念什么吗?
答案 0 :(得分:1)
正如@Mike Zboray在评论中提到的那样,由于嵌套任务,我需要调用task.Unwrap().ContinueWith()
。仅当将Task.Factory.StartNew()
用作Task.Run()
时,才有必要。
我的最终代码如下:
var task = Task.Factory.StartNew(
() => _db.addData(),
CancellationToken.None,
TaskCreationOptions.None,
_taskScheduler);
task.Unwrap().ContinueWith(continuationTask =>
{
if (continuationTask .Exception != null)
{
_logger.LogError(continuationTask.Exception, "Failed to log mismatch");
}
},
_taskScheduler);