在开发一些ASP.Net应用程序时,我遇到了一些空引用问题。 异常如下所示:
Description: The process was terminated due to an unhandled exception.
Exception Info: System.NullReferenceException
Stack:
at System.Threading.Tasks.AwaitTaskContinuation.<ThrowAsyncIfNecessary>b__1(System.Object)
at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
at System.Threading.ThreadPoolWorkQueue.Dispatch()
在通过Google和SO进行搜索后,很可能是由于我的代码以fire and forget异步任务的方式产生了问题。
public interface IRepeatedTaskRunner
{
Task Start();
void Pause();
}
public class RepeatedTaskRunner : IRepeatedTaskRunner
{
public async Task Start() //this is returning Task
{
...
}
}
public class RepeatedTaskRunnerManager{
private IRepeatedTaskRunner _runner;
public void Foo(){
_runner.Start(); //this is not awaited.
}
}
我认为这与这个问题非常相似 "Fire and forget async method in asp.net mvc",但并不完全相同,因为我的代码不在控制器上并且不接受请求。我的代码专门用于运行后台任务。
与上述SO问题相同,通过将代码更改为以下内容可以解决问题,但我想知道为什么以及使用fire-and-forgetting async Task和从Task.Run返回的Task之间有什么区别:
public interface IRepeatedTaskRunner
{
Task Start();
void Pause();
}
public class RepeatedTaskRunner : IRepeatedTaskRunner
{
public Task Start() // async is removed.
{
...
}
}
public class RepeatedTaskRunnerManager{
private IRepeatedTaskRunner _runner;
public void Foo(){
Task.Run(() => _runner.Start()); //this is not waited.
}
}
从我的角度来看,这两个代码只是创建一个任务并忘记它。唯一的区别在于第一个没有在任务上使用await。这会导致行为上的差异吗?
我意识到fire and forget模式的限制和不良影响,来自其他SO问题的了解。
Foo
方法的调用者没有提供正确的同步上下文(使用默认的ASP.Net上下文),这会尝试返回到当前请求的线程。 - Alexei Levenkovawait
会捕获当前的同步上下文(请参见https://dev59.com/eHLYa4cB1Zd3GeqPa7ZV以尝试避免这种情况 - 即Task.Run
是一个好选择)。对于不能返回到请求线程的方法,您需要强制使用不在执行完成时回调请求线程的上下文(因为该线程可能正在运行其他请求或已经结束)。还可以查看http://blogs.msdn.com/b/pfxteam/archive/2012/02/02/await-synchronizationcontext-and-console-apps-part-3.aspx(以及第1/2部分)。 - Alexei Levenkov