我偶尔会遇到一个类似于Task.Run()/ Task.Factory.StartNew()的问题,所以我认为必须有一些非常基本的东西,我不了解它的用法(对于那些就像花括号一样,我为不得不混淆VB而道歉:
我有一个使用以下代码的异步方法:
Try
Using context As New ECOSSContext
context.Meters.Attach(entity)
Await Task.Run(Sub() _
context.SaveChanges() _
)
'ANY CODE HERE NEVER GETS FIRED
End Using
Return True
Catch ex As Exception
Return False
End Try
从同步方法调用它:
Dim result = ModelService.MeterResolution.SaveMeter(data).Result
从理解开始,这应该等到SaveMeter()方法返回结果。我之前列出的异步方法应该等待Task.Run行,直到它返回,然后继续(因此等待)。相反,会发生的是,一旦Await线被击中,callstack似乎就会退出。 SaveChanges()成功,但我无法告知客户这个事实。
我在不同的应用程序中相对频繁地使用TPL并且没有遇到这些问题,但是我没有像context.SaveChanges()那样的方法。
任何建议都表示赞赏。我希望我不只是误读了文档。
答案 0 :(得分:3)
问题实际上是由于您使用了Result
。从同步代码调用async
代码可能非常棘手。
我解释full reasons for this deadlock on my blog。简而言之,默认情况下会在每个await
的开头保存一个“上下文”,用于恢复该方法。
因此,如果在UI或ASP.NET上下文中调用它,则await
完成时,async
方法会尝试重新进入该上下文以继续执行。不幸的是,使用Result
(或Wait
)的代码将阻止该上下文中的线程,因此async
方法无法完成。
避免这种情况的指导原则是:
ConfigureAwait(continueOnCapturedContext: false)
。这使您的async
方法可以继续执行,而无需重新输入上下文。async
。使用await
代替Result
或Wait
。