Result、ConfigAwait、ValueTask
参照:
C# Async/Await: ConfigAwait, ValueTask是个啥?对提高性能有用么?_哔哩哔哩_bilibili
理解ValueTask - 知乎 (zhihu.com)
Demo:https://files.cnblogs.com/files/summerZoo/AsyncAwaitAdvance.zip?t=1647483629
- Result
定义:
1、访问属性的 get 访问器会使当前线程等待(阻塞当前线程),直到异步操作完成;
2、效果像调用 Wait一样当前线程等待异步线程执行完,可用GetAwaiter().GetResult()替代
3、操作结果可用后,将存储该结果,在后续调用 属性时立即 Result 返回。若发生没有返回值的异常采用 AggregateException 捕获。
public TResult Result { get; }
用处:可用于在同步方法里用同步的方式调用异步方法
但是对于程序性能的考虑尽量不要采用这种方式,在winform里用Result会卡死调用的UI线程,可能还会因为在winform默认ConfigAwait为true的原因形成死锁
尽量采用异步async/await的方式去提高程序的性能。
例子:
class Program
{
static void Main(string[] args)
{
AsyncNoReturn().Wait();
int s = AsyncMethod().GetAwaiter().GetResult();
int m = AsyncMethod().Result;
}
public static async Task<int> AsyncMethod()
{
await Task.Delay(500);
return 22;
}
public static async Task AsyncNoReturn()
{
await Task.Delay(500);
}
}
- ConfigAwait
定义:配置用于等待此 Task的 awaiter
如下图若配置flag = true,则RunSomethingAsync在执行完毕后,返回原来线程ID为1的线程继续执行After Await的代码部分;
若配置flag = false,则RunSomethingAsync在执行完毕后,从线程池随机返回一个空闲的线程执行After Await的代码部分;
public async Task RunTask()
{
// Before Await;线程ID:1
await RunSomethingAsync().ConfigAwait(flag);
// After Await;
}
应用:
在Winform、WPF里,基本上ConfigAwait默认设置为true,因为在程序里有大量需要UI线程才能执行的操作
,After Await里有相关UI的操作,ConfigAwait配置成false,在完成RunSomethingAsync()后,随机从线程池拿一个空闲线程来继续往下执行After Await,若这个线程不是原有的UI线程则会出现异常。
除去上述情况下,我们把ConfigAwait设置成false,不要求在原来线程上继续执行可提高性能。
- ValueTask
ValueTask的数据结构比Task的数据结构小,在合适的场景下可使用替代Task,降低内存分配开销。
从本质上来讲ValueTask是一个结构体,Task是一个类。
在返回信息比较少的场景,比如Task
适合场景:
1、运行吞吐量非常高的服务时,我们仍然关心怎么尽可能多地避免内存分配
使用条件:
- 不需要多次
await task
- 在非并发
await
场景(比如和WhenAny、WhenAll、ContinueWhenAll等组合器一起使用处理并发的场景) - 在Async方法被异步调用时,比如AsyncMethod().GetAwaiter().GetResult()、AsyncMethod().Result就不适合