MVC异步控制器动作

时间:2017-02-08 01:46:50

标签: c# asp.net-mvc asp.net-mvc-4 asynchronous .net-core

假设我们在标准mvc控制器中有以下两种方法。

public class SomeController : Controller
{
    public async Task<Response> SomeAction1()
        => await _someService.SomeAsyncMethod();

    public Task<Response> SomeAction2()
        => _someService.SomeAsyncMethod();

    // SomeAsyncMethod might look like this.
    // public async Task<Response> SomeAsyncMethod()
    //    => await someDbAction();
}

简单问题:基本控制器类是否执行等待/异步的任务?

或者,这两个动作都做同样的事情吗?

- 编辑稍作澄清。 -

https://docs.microsoft.com/en-us/aspnet/mvc/overview/performance/using-asynchronous-methods-in-aspnet-mvc-4

  

线程池如何处理请求

     

在Web服务器上,.NET Framework维护一个用于为ASP.NET请求提供服务的线程池。当请求到达时,将调度池中的线程来处理该请求。如果同步处理请求,则在处理请求时处理请求的线程正忙,并且该线程无法为另一个请求提供服务。

我的目标是了解返回任务的方法是否需要附带单词async。如果关键字不是,那么即使SomeAsyncMethod中有await创建回调,它会将该方法视为同步并保留该线程吗?

2 个答案:

答案 0 :(得分:3)

  

这两个动作是否完全相同?

完全。虽然它们都有相同的效果。每当您将方法标记为async并且在方法体中具有一个或多个await表达式时,编译器将生成一个状态机,用于在await调用后异步恢复该方法。

但是,由于方法体是返回Task<Action>的单个方法调用,所有编译器机制都是无用的,直接返回Task将导致编译代码更小。

在运行时,您可能不会注意到差异,除非async Task<Action>案例的执行时间略高。

答案 1 :(得分:1)

我使用await制作了两个简化的测试方法,只执行并返回Task

private static async Task<int> TestAwait()
{
    await Task.Delay(1000);
    return 0;
}

private static Task Test()
{
    return Task.Delay(1000);
}

为这两者生成的IL非常不同:

TestAwait:
IL_0000:  newobj      UserQuery+<TestAwait>d__0..ctor
IL_0005:  stloc.0     
IL_0006:  ldloc.0     
IL_0007:  call          System.Runtime.CompilerServices.AsyncTaskMethodBuilder<System.Int32>.Create
IL_000C:  stfld       UserQuery+<TestAwait>d__0.<>t__builder
IL_0011:  ldloc.0     
IL_0012:  ldc.i4.m1   
IL_0013:  stfld       UserQuery+<TestAwait>d__0.<>1__state
IL_0018:  ldloc.0     
IL_0019:  ldfld       UserQuery+<TestAwait>d__0.<>t__builder
IL_001E:  stloc.1     
IL_001F:  ldloca.s    01 
IL_0021:  ldloca.s    00 
IL_0023:  call        System.Runtime.CompilerServices.AsyncTaskMethodBuilder<System.Int32>.Start<<TestAwait>d__0>
IL_0028:  ldloc.0     
IL_0029:  ldflda      UserQuery+<TestAwait>d__0.<>t__builder
IL_002E:  call        System.Runtime.CompilerServices.AsyncTaskMethodBuilder<System.Int32>.get_Task
IL_0033:  ret

<TestAwait>d__0.MoveNext:
IL_0000:  ldarg.0     
IL_0001:  ldfld       UserQuery+<TestAwait>d__0.<>1__state
IL_0006:  stloc.0     
IL_0007:  ldloc.0     
IL_0008:  brfalse.s   IL_000C
IL_000A:  br.s        IL_000E
IL_000C:  br.s        IL_004C
IL_000E:  nop         
IL_000F:  ldc.i4      E8 03 00 00 
IL_0014:  call        System.Threading.Tasks.Task.Delay
IL_0019:  callvirt    System.Threading.Tasks.Task.GetAwaiter
IL_001E:  stloc.2     
IL_001F:  ldloca.s    02 
IL_0021:  call        System.Runtime.CompilerServices.TaskAwaiter.get_IsCompleted
IL_0026:  brtrue.s    IL_0068
IL_0028:  ldarg.0     
IL_0029:  ldc.i4.0    
IL_002A:  dup         
IL_002B:  stloc.0     
IL_002C:  stfld       UserQuery+<TestAwait>d__0.<>1__state
IL_0031:  ldarg.0     
IL_0032:  ldloc.2     
IL_0033:  stfld       UserQuery+<TestAwait>d__0.<>u__1
IL_0038:  ldarg.0     
IL_0039:  stloc.3     
IL_003A:  ldarg.0     
IL_003B:  ldflda      UserQuery+<TestAwait>d__0.<>t__builder
IL_0040:  ldloca.s    02 
IL_0042:  ldloca.s    03 
IL_0044:  call        System.Runtime.CompilerServices.AsyncTaskMethodBuilder<System.Int32>.AwaitUnsafeOnCompleted<TaskAwaiter,<TestAwait>d__0>
IL_0049:  nop         
IL_004A:  leave.s     IL_00AB
IL_004C:  ldarg.0     
IL_004D:  ldfld       UserQuery+<TestAwait>d__0.<>u__1
IL_0052:  stloc.2     
IL_0053:  ldarg.0     
IL_0054:  ldflda      UserQuery+<TestAwait>d__0.<>u__1
IL_0059:  initobj     System.Runtime.CompilerServices.TaskAwaiter
IL_005F:  ldarg.0     
IL_0060:  ldc.i4.m1   
IL_0061:  dup         
IL_0062:  stloc.0     
IL_0063:  stfld       UserQuery+<TestAwait>d__0.<>1__state
IL_0068:  ldloca.s    02 
IL_006A:  call        System.Runtime.CompilerServices.TaskAwaiter.GetResult
IL_006F:  nop         
IL_0070:  ldloca.s    02 
IL_0072:  initobj     System.Runtime.CompilerServices.TaskAwaiter
IL_0078:  ldc.i4.0    
IL_0079:  stloc.1     
IL_007A:  leave.s     IL_0096
IL_007C:  stloc.s     04 
IL_007E:  ldarg.0     
IL_007F:  ldc.i4.s    FE 
IL_0081:  stfld       UserQuery+<TestAwait>d__0.<>1__state
IL_0086:  ldarg.0     
IL_0087:  ldflda      UserQuery+<TestAwait>d__0.<>t__builder
IL_008C:  ldloc.s     04 
IL_008E:  call        System.Runtime.CompilerServices.AsyncTaskMethodBuilder<System.Int32>.SetException
IL_0093:  nop         
IL_0094:  leave.s     IL_00AB
IL_0096:  ldarg.0     
IL_0097:  ldc.i4.s    FE 
IL_0099:  stfld       UserQuery+<TestAwait>d__0.<>1__state
IL_009E:  ldarg.0     
IL_009F:  ldflda      UserQuery+<TestAwait>d__0.<>t__builder
IL_00A4:  ldloc.1     
IL_00A5:  call        System.Runtime.CompilerServices.AsyncTaskMethodBuilder<System.Int32>.SetResult
IL_00AA:  nop         
IL_00AB:  ret         

<TestAwait>d__0.SetStateMachine:
IL_0000:  ret         

<TestAwait>d__0..ctor:
IL_0000:  ldarg.0     
IL_0001:  call        System.Object..ctor
IL_0006:  nop         
IL_0007:  ret         

-------------- END OF TESTAWAIT

Test:
IL_0000:  nop         
IL_0001:  ldc.i4      E8 03 00 00 
IL_0006:  call        System.Threading.Tasks.Task.Delay
IL_000B:  stloc.0     
IL_000C:  br.s        IL_000E
IL_000E:  ldloc.0     
IL_000F:  ret

因此编译器为TestAwait

生成的代码量非常可观