c#异步async和await
包含await表达式/语句的方法,为异步方法,方法声明必须标记为async。(反之不一定,async标记的方法,可以没有await表达式,那就是正常的方法,编译器只是警告而已)
作用和机制:
await 用来指定(当前异步方法的)暂停点。 await
运算符通知编译器异步方法:在等待的异步过程(await 表达式)完成后才能继续通过该点。 同时,控制返回至异步方法的调用方。这样主线程就会继续执行。
异步方法在 await
表达式执行时暂停并不构成方法退出(只是暂停本方法,等await 语句完成后继续执行),只会导致 finally
代码块不运行。
返回类型:
1,如果异步方法包含指定 TResult
类型操作数的 return
语句,将 Task<TResult> 指定为返回类型。例如:public
async Task<int> GetLeisureHoursAsync(){}
2,如果异步方法不含任何 return 语句或包含不返回操作数的 return 语句,将 Task 用作返回类型。例如:
public async Task ShowTodaysInfoAsync(){}
3,返回void,仅适用于事件处理程序,例如:public async void
OnButtonClicked1
(){}(注意无法等待返回 void
的异步方法, 所以不能这么写:await
())OnButtonClicked1
4,从 C# 7.0 开始,异步方法可返回任何具有可访问的 GetAwaiter
方法的类型。
Task 和 Task<TResult> 是引用类型,因此,性能关键路径中的内存分配会对性能产生负面影响,尤其当分配出现在紧凑循环中时。 支持通用返回类型意味着可返回轻量值类型(而不是引用类型),从而避免额外的内存分配,.NET 提供 System.Threading.Tasks.ValueTask<TResult> 结构作为返回任务的通用值的轻量实现,例如:
static async ValueTask<int> RollAsync() { await Task.Delay(500); int diceRoll = s_rnd.Next(1, 7); return diceRoll; }
await使用方式:
1,await
语句,执行后不返回值
WaitAndApologizeAsync
方法不包含 return
语句或者不返回任何结果的return语句,应用此方式: await SomeTaskMethodAsync()
2,await
表达式,执行并获取返回值
SomeTaskMethodAsync
方法返回Task<TResult>,应用此方式: T result = await SomeTaskMethodAsync<T>();
也就是说
await
会从 Task<TResult>
中检索结果TResult,赋值给result
此表达式也可以分离成两句:
Task t=SomeTaskMethodAsync<T>();//这里不暂停
T result=await t;//到这里才暂停
多线程:
async
和 await
关键字不会创建其他线程。 因为异步方法不会在其自身线程上运行,因此它不需要多线程
注意:
异步方法无法声明 in、ref 或 out 参数,但可以调用包含此类参数的方法。 同样,异步方法无法通过引用返回值,但可以调用包含 ref 返回值的方法。
Task.Result 属性为阻止属性。 如果你在其任务完成之前尝试访问它,当前处于活动状态的线程将被阻止,直到任务完成且值为可用。 在大多数情况下,应通过使用 await
访问此值,而不是直接访问属性。