C# 使用和不使用async声明的lambdas之间有区别吗
当lambdasC# 使用和不使用async声明的lambdas之间有区别吗,c#,asynchronous,lambda,async-await,C#,Asynchronous,Lambda,Async Await,当lambdas()=>DoSomethingAsync()和async()=>wait DoSomethingAsync()都键入为Func时,两者之间是否有区别?我们应该选择哪一个?什么时候 这里是一个简单的控制台应用程序 using System; using System.Threading.Tasks; namespace asyncDemo { class Program { static void Main(string[] args)
()=>DoSomethingAsync()
和async()=>wait DoSomethingAsync()
都键入为Func
时,两者之间是否有区别?我们应该选择哪一个?什么时候
这里是一个简单的控制台应用程序
using System;
using System.Threading.Tasks;
namespace asyncDemo
{
class Program
{
static void Main(string[] args)
{
var demo = new AsyncDemo();
var task = demo.RunTheDemo();
task.Wait();
Console.ReadLine();
}
}
public class AsyncDemo
{
public async Task Runner(Func<Task> action)
{
Console.WriteLine(DateTime.Now.ToLongTimeString() + " Launching the action");
await action();
}
private async Task DoSomethingAsync(string suffix)
{
await Task.Delay(2000);
Console.WriteLine(DateTime.Now.ToLongTimeString() + " Done something, " + suffix);
}
public async Task RunTheDemo()
{
await Runner(() => DoSomethingAsync("no await"));
await Runner(async () => await DoSomethingAsync("with await"));
}
}
}
所以在RunTheDemo
中,对的两个调用都等待Runner(someLambda)代码>似乎以相同的定时特性执行相同的操作-两者都具有正确的两秒延迟
这两条线都能工作,所以它们完全相等吗?()=>DoSomethingAsync()
和async()=>wait-DoSomethingAsync()
构造之间有什么区别?我们应该选择哪一个?什么时候
这与“在一般情况下我是否应该使用await
”的问题不同,因为这里我们处理的是异步代码,lambda类型为Func
,在消费方法中正确地等待。问题涉及如何声明这些lambda,以及该声明的效果。这是IL Viewer针对这两种方法的输出:
await Runner(() => DoSomethingAsync("no await"));
.method private hidebysig instance class [mscorlib]System.Threading.Tasks.Task
'<RunTheDemo>b__5_0'() cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor()
= (01 00 00 00 )
.maxstack 8
// [42 32 - 42 60]
IL_0000: ldarg.0 // this
IL_0001: ldstr "no await"
IL_0006: call instance class [mscorlib]System.Threading.Tasks.Task TestClass::DoSomethingAsync(string)
IL_000b: ret
} // end of method CompanyManagementController::'<RunTheDemo>b__5_0'
await Runner(async () => await DoSomethingAsync("with await"));
.method private hidebysig instance class [mscorlib]System.Threading.Tasks.Task
'<RunTheDemo>b__5_1'() cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.AsyncStateMachineAttribute::.ctor(class [mscorlib]System.Type)
= (
01 00 45 57 65 62 43 61 72 64 2e 43 6f 6e 74 72 // ..TestClass
6f 6c 6c 65 72 73 2e 43 6f 6d 70 61 6e 79 4d 61 // +<<RunTheDemo>
6e 61 67 65 6d 65 6e 74 43 6f 6e 74 72 6f 6c 6c // b__5_1>d..
65 72 2b 3c 3c 52 75 6e 54 68 65 44 65 6d 6f 3e
62 5f 5f 35 5f 31 3e 64 00 00
)
// MetadataClassType(TestClass+<<RunTheDemo>b__5_1>d)
.custom instance void [mscorlib]System.Diagnostics.DebuggerStepThroughAttribute::.ctor()
= (01 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor()
= (01 00 00 00 )
.maxstack 2
.locals init (
[0] class TestClass/'<<RunTheDemo>b__5_1>d' V_0,
[1] valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder V_1
)
IL_0000: newobj instance void TestClass/'<<RunTheDemo>b__5_1>d'::.ctor()
IL_0005: stloc.0 // V_0
IL_0006: ldloc.0 // V_0
IL_0007: ldarg.0 // this
IL_0008: stfld class TestClass TestClass/'<<RunTheDemo>b__5_1>d'::'<>4__this'
IL_000d: ldloc.0 // V_0
IL_000e: call valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder::Create()
IL_0013: stfld valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder TestClass/'<<RunTheDemo>b__5_1>d'::'<>t__builder'
IL_0018: ldloc.0 // V_0
IL_0019: ldc.i4.m1
IL_001a: stfld int32 TestClass/'<<RunTheDemo>b__5_1>d'::'<>1__state'
IL_001f: ldloc.0 // V_0
IL_0020: ldfld valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder TestClass/'<<RunTheDemo>b__5_1>d'::'<>t__builder'
IL_0025: stloc.1 // V_1
IL_0026: ldloca.s V_1
IL_0028: ldloca.s V_0
IL_002a: call instance void [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder::Start<class TestClass/'<<RunTheDemo>b__5_1>d'>(!!0/*class TestClass/'<<RunTheDemo>b__5_1>d'*/&)
IL_002f: ldloc.0 // V_0
IL_0030: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder TestClass/'<<RunTheDemo>b__5_1>d'::'<>t__builder'
IL_0035: call instance class [mscorlib]System.Threading.Tasks.Task [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder::get_Task()
IL_003a: ret
} // end of method CompanyManagementController::'<RunTheDemo>b__5_1'
wait Runner(()=>DoSomethingAsync(“无等待”);
.method私有隐藏实例类[mscorlib]System.Threading.Tasks.Task
“b__5_0”(cil管理)
{
.custom instance void[mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor()
= (01 00 00 00 )
.maxstack 8
// [42 32 - 42 60]
IL_0000:ldarg.0//
IL_0001:ldstr“无等待”
IL_0006:调用实例类[mscorlib]System.Threading.Tasks.Task TestClass::DoSomethingAsync(字符串)
IL_000b:ret
}//方法结束CompanyManagementController::'b__5_0'
wait Runner(async()=>wait DoSomethingAsync(“with await”));
.method私有隐藏实例类[mscorlib]System.Threading.Tasks.Task
“b__5_1”(cil管理)
{
.custom instance void[mscorlib]System.Runtime.CompilerServices.AsyncStateMachineAttribute::.ctor(类[mscorlib]System.Type)
= (
01 00 45 57 65 62 43 61 72 64 2e 43 6f 6e 74 72/…测试等级
6f 6c 6c 65 72 73 2e 43 6f 6d 70 61 6e 79 4d 61/+d。。
65 72 2b 3c 3c 52 75 6e 54 68 65 44 65 6d 6f 3e
62 5f 5f 35 5f 31 3e 64 00 00
)
//MetadataClassType(TestClass+d)
.custom instance void[mscorlib]System.Diagnostics.DebuggerStepThroughAttribute::.ctor()
= (01 00 00 00 )
.custom instance void[mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor()
= (01 00 00 00 )
.maxstack 2
.init(
[0]类TestClass/'d'V_0,
[1] valuetype[mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder V_1
)
IL_0000:newobj实例void TestClass/'d':.ctor()
IL_0005:stloc.0//V_0
IL_0006:ldloc.0//V_0
IL_0007:ldarg.0//
IL_0008:stfld类TestClass TestClass/'d':'4_this'
IL_000d:ldloc.0//V_0
IL_000e:调用valuetype[mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder[mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder::Create()
IL_0013:stfld valuetype[mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder TestClass/'d':'t_uBuilder'
IL_0018:ldloc.0//V_0
IL_0019:ldc.i4.m1
IL_001a:stfld int32 TestClass/'d':'1_状态'
IL_001f:ldloc.0//V_0
IL_0020:ldfld valuetype[mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder TestClass/'d':'t_uBuilder'
IL_0025:stloc.1//V_1
IL_0026:ldloca.s V_1
IL_0028:ldloca.s V_0
IL_002a:调用实例void[mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder::Start(!!0/*类TestClass/'d'*/&)
IL_002f:ldloc.0//V_0
IL_0030:ldflda valuetype[mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder TestClass/'d':'t_uBuilder'
IL_0035:调用实例类[mscorlib]System.Threading.Tasks.Task[mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder::get_Task()
IL_003a:ret
}//方法结束CompanyManagementController::'b_u5_1'
第二个是使用异步状态机是的,它们是相同的,但这是一个相当简单的例子。这两者在功能上是等效的,使用async
时,您只需要(可能,取决于编译器)做更多的工作
了解async
lambda之所以有用的一个更好的例子是,如果您需要处理一系列异步操作,那毕竟是wait
的目的:
await Runner(async () => await DoSomethingAsync(await httpClient.Get("www.google.com")));
使用和不使用async声明的lambdas之间有区别吗
是的,有区别。一个是异步lambda,另一个只是返回lambda的任务
异步lambda编译到状态机中,而另一个不编译到状态机中,因此异步lambda具有不同的异常语义,因为异常封装在返回的任务中,不能同步抛出
这与常规方法中存在的差别完全相同。例如,在此异步方法之间:
async Task FooAsync()
{
await DoSomethingAsync("with await");
}
此任务返回方法:
Task FooAsync()
{
return DoSomethingAsync("no await");
}
查看这些方法可以更清楚地显示它们之间的差异,但是lambda只是语法上的糖分,实际上被编译成与这些方法行为相同的方法
我们应该选择哪一个?什么时候
这取决于你的品味。使用async关键字生成的状态机性能不如简单地返回任务。然而,在某些情况下,异常语义可能令人惊讶
以这段代码为例:
Hamster hamster = null;
Func<Task> asyncAction = () => FooAsync(hamster.Name);
var task = asyncAction();
try
{
await task;
}
catch
{
// handle
}
我个人使用任务返回lambda来表示这些单行表达式lambda,因为它们通常非常简单。但是我的团队在经历了一些极其有害的错误之后,总是使用async
和wait
关键字。基本上是编译器简化lambda并自动从DoSomething返回任务。。。添加括号,现在它就结束了,您必须执行异步或手动返回任务
Hamster hamster = null;
Func<Task> asyncAction = () => FooAsync(hamster.Name);
var task = asyncAction();
try
{
await task;
}
catch
{
// handle
}
Func<Task> asyncAction = async () => await FooAsync(hamster.Name);