我有一个ASPX页面,我无法将其转换为async
,但是在同步上下文中使用了一些async
方法。它调用它们的方式如下:
public void MySyncMethod()
{
var myTask = Task.Run(() => _myField.DoSomethingAsync());
myTask.Wait();
//use myTask.Result
}
就async/await
和/或封锁而言,执行此操作与后续操作之间是否有区别?
public void MySyncMethod()
{
var myTask = _myField.DoSomethingAsync(); //just get the Task direct, no Task.Run
myTask.Wait();
//use myTask.Result
}
我假设是以前的开发人员添加Task.Run
的原因。但是当工作在不同的线程上运行时,我遇到了访问HttpContext
中的内容的问题。
这里是否有理由使用Task.Run
?
答案 0 :(得分:3)
这样做与后续操作之间是否有任何区别 异步/等待和/或阻止?
是的,第一段代码使用线程池线程,然后等待它返回,因此您使用两个线程而不是一个。他们都封锁了。
我假设以前的开发人员添加Task.Run是有原因的。
是的,从ASP.Net上下文对async
代码进行(直接)阻止是bad idea and can cause deadlocks。因此,第二个代码块(在线程使用方面)效率更高,但会遇到严重的死锁问题。
此处的正确解决方案是制作public void MySyncMethod()
async
本身(public async Task MySyncMethod()
)。这两种解决方案都有缺点,唯一的解决方法是制作整个调用堆栈async
。 如果可以的话,就这么做。
如果您无法从另一个async
方法中调用async
方法,则可以使用Task.Run
。有关更多详细信息,请参见How to call asynchronous method from synchronous method in C#?。
如果您想在线程中HttpContext
读入Using HttpContext in Async Task,我绝对会赞成:
这些答案的选项并牢记
答案 1 :(得分:0)
基于async
/ await
的异步代码的内部工作原理与Task.Run
启动的任务根本不同。 async
/ await
任务是基于承诺的,并且取决于调用者在适当情况下是否配合将执行返回给异步方法。由Task.Run
启动的任务通常在线程池中的并行线程上启动,并且在适当的时候不依赖于调用方的合作来继续执行。
这个星座导致一个问题,您不能将基于promise的任务与其他任务一样对待,因为基于promise的任务可能会等待调用方的合作以返回执行,这可能不会发生,因为其他任务是独立执行,可能会等待调用者。结果是死锁。
解决方案是specific Task.Run
overload,它将为现有的基于任务的方法创建代理,该方法允许正确执行基于promise的任务。在此代理上调用Wait
是安全的。这就是为什么其他开发人员使用此构造的原因。他还可以简化呼叫并避免使用像这样的匿名方法:
var myTask = Task.Run(_myField.DoSomethingAsync);