C# 7 带有更灵活的 await 关键字;它现在可以等待任何提供 GetAwaiter 方法的对象。一种可用于等待的新类型是 ValueTask。与 Task 类相反,ValueTask 是一个结构。这具有性能优势,因为 ValueTask 在堆上没有对象。
与异步方法调用相比,Task 对象的实际开销是多少?需要异步调用的方法通常比堆上的对象有更多的开销。大多数时候,堆上 Task 对象的开销是可以忽略的,但并不总是这样。例如,某方法可以有一个路径,其中数据是从一个具有异步 API 的服务中检索出来的。通过这种数据检索,数据就写入到本地缓存中。第二次调用该方法时,可以以快速的方式检索数据,而不需要创建 Task 对象。
示例方法 GreetingValueTaskAsync 正是这样做的。如果该名称已存在于字典中,则结果返回为 ValueTask。如果名称不在字典中,将调用 GreetingAsync 方法,该方法返回一个 Task。在此任务中等待检索结果时,将再次返回 ValueTask:
private readonly static Dictionary<string, string> names = new Dictionary<string, string>();
static async ValueTask<string> GreetingValueTaskAsync(string name)
{if (names.TryGetValue(name, out string result)){return result;}else{result = await GreetingAsync(name);names.Add(name, result); return result;}}
}
UseValueTask 方法使用相同的名称调用 GreetingValueTaskAsync 方法两次。第一次使用 GreetingAsync 方法检索数据;第二次,数据在字典中找到并从那里返回:
private static async void UseValueTask()
{string result = await GreetingValueTaskAsync("Katharina"); Console.WriteLine(result);string result2 = await GreetingValueTaskAsync("Katharina"); Console.WriteLine(result2);
}
如果方法不使用 async 修饰符,而需要返回 ValueTask,就可以使用传递结果或者传递 Task 对象的构造函数创建 ValueTask 对象:
static ValueTask<string> GreetingValueTask2Async(string name)
{if(names.TryGetValue(name, out string result)){return new ValueTask<string>(result);}else{Task<string> tl = GreetingAsync(name);TaskAwaiter<string> awaiter = tl.GetAwaiter();awaiter.OnCompleted(OnCompletion); return new ValueTask<string>(t1):void OnCompletion(){namea.Add(name, awaiter.GetResult());}}
}
往期推荐
· C# 数据流
· C# 类型系统
· C# 面向对象的编程
· C# 执行 SQL 语句
· C# 连接数据库
· C# 迭代器
Love life,love yourself
关注小编不迷路呦~