假设我们在标准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();
}
简单问题:基本控制器类是否执行等待/异步的任务?
或者,这两个动作都做同样的事情吗?
- 编辑稍作澄清。 -
线程池如何处理请求
在Web服务器上,.NET Framework维护一个用于为ASP.NET请求提供服务的线程池。当请求到达时,将调度池中的线程来处理该请求。如果同步处理请求,则在处理请求时处理请求的线程正忙,并且该线程无法为另一个请求提供服务。
我的目标是了解返回任务的方法是否需要附带单词async
。如果关键字不是,那么即使SomeAsyncMethod
中有await
创建回调,它会将该方法视为同步并保留该线程吗?
答案 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