我应该使用Task.Run在同步上下文中等待任务吗?

时间:2018-08-17 09:38:41

标签: c# asp.net async-await

我有一个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

2 个答案:

答案 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,我绝对会赞成:

这些答案的选项并牢记

  

First off, you're not creating a copy of the object, you're just copying the reference to the object.HttpContext isn't a struct.....etc

答案 1 :(得分:0)

基于async / await的异步代码的内部工作原理与Task.Run启动的任务根本不同。 async / await任务是基于承诺的,并且取决于调用者在适当情况下是否配合将执行返回给异步方法。由Task.Run启动的任务通常在线程池中的并行线程上启动,并且在适当的时候不依赖于调用方的合作来继续执行。

这个星座导致一个问题,您不能将基于promise的任务与其他任务一样对待,因为基于promise的任务可能会等待调用方的合作以返回执行,这可能不会发生,因为其他任务是独立执行,可能会等待调用者。结果是死锁。

解决方案是specific Task.Run overload,它将为现有的基于任务的方法创建代理,该方法允许正确执行基于promise的任务。在此代理上调用Wait是安全的。这就是为什么其他开发人员使用此构造的原因。他还可以简化呼叫并避免使用像这样的匿名方法:

var myTask = Task.Run(_myField.DoSomethingAsync);