如果我们有一个ASP.NET异步操作来返回任务的结果,您是否应该忽略async / await关键字?

如果我有以下代码:

public async Task<SomeObject> actionmethodAsync()
{
   return await someAsyncMethod();
}

我应该将其更改为:

public SomeObject actionmethod()
{
   return someAsyncMethod().Getawaiter().GetResult();
}

我不确定一旦控制权返回给actionmethodAsync的调用者,究竟会发生什么,是否有任何益处。

它是否会产生与编译器following编译的代码类似的结果,或者它是IIS提供的线程池线程,并且如果我们沿着等待路线走,它不会被阻塞?我觉得无论选择哪个选项,我们都将继续使用单个线程。 (没有切换线程上下文和异步状态机的额外费用。)

yitianshici 回答:如果我们有一个ASP.NET异步操作来返回任务的结果,您是否应该忽略async / await关键字?

使用async/await将允许IIS线程临时驻留等待任务的请求(通常是异步I / O请求),做其他工作(服务新的传入请求,恢复以前等待任务的其他请求),并在完成相应任务后恢复它们,从而提高吞吐量。

来源: https://docs.microsoft.com/en-us/dotnet/standard/async-in-depth#what-does-this-mean-for-a-server-scenario

,

您链接到的答案是关于控制台应用程序的,所以情况就不同了。

Microsoft有一些关于Asynchronous programming with async and await的写得很好的文章,值得一读。它使用做早餐的示例确实有助于理解异步编程的全部内容。

要记住的关键是,ASP.NET可以使用的线程数没有上限。 It's configurable,但总会有最大值。因此,使用一个线程可以做的越多越好。

让我们以一些实数为例。每个CPU的默认线程数为20。因此,假设您使用的是四核处理器。最大线程数将为80(如果将超线程算作额外的CPU,则实际上可能为160,但是我们会说80)。

现在让我们说同时有80个HTTP请求,所有这些都需要发出I / O请求(例如到数据库)。它们都在同一时间被处理,并开始其I / O请求。现在,当他们等待响应时,又有另一个请求进来。它发生什么将取决于您的代码是否异步。

  • 如果代码是同步的,则所有80个线程均被锁定,等待响应。这样,直到这80个请求之一完成,第81个请求才会得到满足。
  • 如果您的代码是异步的,则所有80个线程将免费,并且第81个请求将立即得到处理。当每个I / O请求完成时,它会放在80个线程中的一个上以完成并返回响应给调用者。

异步编程并不是要更快地返回单个请求(实际上,它会稍微慢一些)。这与应用程序的总体性能有关。

现在,继续您的示例。有一个您没有考虑的选项,就是不等待而返回Task

public Task<SomeObject> ActionMethodAsync()
{
   return someAsyncMethod();
}

这将边缘(可能实际上并不明显)更快。 an old question about that的答案很好,但总而言之:

  • 如果您仅调用一个异步方法,并且将要返回它的结果,则只需直接返回Task
  • 如果您需要调用多个异步方法,或者需要对异步调用的结果进行一些处理,则必须使用asyncawait
,

还有更多。

这是您应该坚持使用async/await

的一些原因

1。您无意使用GetResult

TaskAwaiter.GetResult Method状态

  

此API支持产品基础结构,不能直接在您的代码中使用。

2。没有await,您的代码将不再异步

通过丢弃await,您将摆脱异步魔术,您的代码将变得同步和阻塞,并且每个请求都使用一个线程,直到完成为止。


很多工作,线程不多。

我希望这个小例子能够展示一个框架处理更多请求的难易程度,然后使用Tasks时会有线程。

考虑一下,因为3名侍应生可以提供10张桌子。

static async Task DoAsync(int index) 
{
    var threadId = Thread.CurrentThread.ManagedThreadId;
    await Task.Delay(TimeSpan.FromMilliseconds(index*100));
    Console.WriteLine($"task: {index},threads: {threadId} -> {Thread.CurrentThread.ManagedThreadId}");
}

public static async Task Main()
{
    Console.WriteLine($"thread: {Thread.CurrentThread.ManagedThreadId}: Main");

    var tasks = Enumerable.Range(0,10).Select( i => DoAsync(i));
    await Task.WhenAll(tasks);

    Console.WriteLine($"thread: {Thread.CurrentThread.ManagedThreadId}: Main Done");
}

输出

thread: 1: Main
task: 0,threads: 1 -> 1
task: 1,threads: 1 -> 4
task: 2,threads: 1 -> 4
task: 3,threads: 1 -> 4
task: 4,threads: 1 -> 4
task: 5,threads: 1 -> 4
task: 6,threads: 1 -> 5
task: 7,threads: 1 -> 5
task: 8,threads: 1 -> 5
task: 9,threads: 1 -> 5
thread: 5: Main Done

正如您所发现的,n线程能够处理x>n请求的意义在Async in depth中明确表示。这对于服务器方案意味着什么?'部分。

  

此模型与典型的服务器方案工作负载一起很好地工作。因为没有专用于阻止未完成任务的线程,所以服务器线程池可以处理大量的Web请求。   (...)

状态机

Asynchronous programming是有关异步/等待的良好信息来源。有两个段落与await == GetAwaiter().GetResult()的简化视图特别相关。

  

幕后发生的事情

     

涉及异步操作的动向很多。如果您对“任务”和“任务”的封面下所发生的事情感到好奇,请查看Async in-depth文章以了解更多信息。

     

在C#方面,编译器将您的代码转换为状态机,以跟踪诸如在达到等待时产生执行以及在后台作业完成后恢复执行之类的情况。

本文链接:https://www.f2er.com/3167897.html

大家都在问