Ответ 1
Короткий ответ
MethodOneAsync()
действительно Async и должен использоваться, но MethodTwoAsync()
не является подлинным Async, поскольку он вызывает поток пула потоков
Длинный ответ
Для тестирования и управления я упростил ваш код следующим образом:
Выполнение из метода Основной Linqpad следующим образом:
var resultTask = MethodOneAsync(); // Comment one the methods
resultTask.Result.Dump();
Фактический код
public async Task<int> DoSomethingAsync(Func<Task<int>> action)
{
return await Task.FromResult<int>(3);
}
public async Task<int> MethodOneAsync()
{
await Task.Delay(10);
return await DoSomethingAsync(async () => await Task.FromResult<int>(3));
}
public async Task<int> MethodOneAsync()
{
await Task.Delay(10);
return await DoSomethingAsync(() => Task.FromResult<int>(3));
}
Теперь я рассмотрел IL generated
между двумя вызовами, а следующее - самое важное различие:
Первый вызов с Async and Await
внутри DoSomethingAsync
имеет следующий IL:
<>c.<MethodOneAsync>b__2_0:
IL_0000: newobj UserQuery+<>c+<<MethodOneAsync>b__2_0>d..ctor
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: ldarg.0
IL_0008: stfld UserQuery+<>c+<<MethodOneAsync>b__2_0>d.<>4__this
IL_000D: ldloc.0
IL_000E: call System.Runtime.CompilerServices.AsyncTaskMethodBuilder<System.Int32>.Create
IL_0013: stfld UserQuery+<>c+<<MethodOneAsync>b__2_0>d.<>t__builder
IL_0018: ldloc.0
IL_0019: ldc.i4.m1
IL_001A: stfld UserQuery+<>c+<<MethodOneAsync>b__2_0>d.<>1__state
IL_001F: ldloc.0
IL_0020: ldfld UserQuery+<>c+<<MethodOneAsync>b__2_0>d.<>t__builder
IL_0025: stloc.1
IL_0026: ldloca.s 01
IL_0028: ldloca.s 00
IL_002A: call System.Runtime.CompilerServices.AsyncTaskMethodBuilder<System.Int32>.Start<<<MethodOneAsync>b__2_0>d>
IL_002F: ldloc.0
IL_0030: ldflda UserQuery+<>c+<<MethodOneAsync>b__2_0>d.<>t__builder
IL_0035: call System.Runtime.CompilerServices.AsyncTaskMethodBuilder<System.Int32>.get_Task
IL_003A: ret
Второй без Async and Await
имеет следующий код:
<>c.<MethodOneAsync>b__2_0:
IL_0000: ldc.i4.3
IL_0001: call System.Threading.Tasks.Task.FromResult<Int32>
IL_0006: ret
Кроме того, у первого есть полный код конечного автомата для дополнительного вызова async await
, который ожидается.
Важные моменты:
- Для вызова метода Async используйте
async () => await SomeActionAsync()
, так как это правда. Выполнение Async и работает с портами завершения ввода-вывода. - В другом случае он вызывает поток
Threadpool
для выполнения Async-метода, что не подходит для асинхронного выполнения
Я могу вставить полный IL, если потребуется, чтобы понять разницу, но лучше всего вы оцениваете то же самое в Visual Studio или LinqPad, чтобы понять нюансы