使用 C# ValueTask,进一步提升你的异步代码性能
|
admin
2025年6月25日 22:7
本文热度 32
|
前言
嗨,程序员小伙伴们,早上好!
今天我们要聊一个能让你的异步代码既快又省的小能手——ValueTask。
如果你还在只用Task写异步代码,那就像开跑车却一直挂一档,太浪费啦!
微软在.NET Core 2.1中悄悄引入了一个性能小怪兽——ValueTask。
它就像Task的轻量级表弟,虽然个头小,但在某些场合下能发挥惊人的威力!
记得我第一次用 ValueTask 优化代码时,那个性能提升简直让我怀疑自己的眼睛。
什么是 ValueTask?
简单来说,ValueTask<T>
是一种结构体(struct),而 Task<T>
则是一个类(class)。
这意味着 ValueTask<T>
可以避免一些不必要的对象分配,从而减少垃圾回收的压力,特别是在高性能要求的场景下尤为重要。
ValueTask vs Task
现在我们来看看 ValueTask
和 Task
的区别:
Task
就像你家的SUV——功能全面但油耗高,每次异步操作都需要在堆(heap)上分配新对象。
ValueTask
则像是一辆混合动力小车——当操作能同步完成时,它直接利用栈(stack)上的值类型,完全避免堆分配!
所以这也是我们选择 ValueTask 的理由:
ValueTask
允许你返回一个已经完成的结果,而不需要创建新的 Task
对象,可以减少内存分配
由于减少了临时对象的创建,使用 ValueTask
可以显著降低垃圾回收器的工作负担
代码对比
// 传统Task方式
public async Task<int> GetDataAsync()
{
// 总会产生堆分配
await Task.Delay(100);
return42;
}
// ValueTask方式
public async ValueTask<int> GetDataOptimizedAsync()
{
// 检查数据是否已经缓存
// 如果是,则直接返回,无堆分配!
// 这里随便返回一个值,实际中,这里是返回缓存中的键值
if (isDataCached) return42;
await Task.Delay(100);
return42;
}
在上面这个例子中,我们可以看到,当结果可以同步获取时,ValueTask 可以避免不必要的堆分配,从而提高性能
什么时候该用ValueTask?
记住这个黄金法则:当你的方法经常(>50%)能同步完成时,用ValueTask。
比如:
总结
无论是为了提高应用的响应速度,还是减少不必要的内存开销,合理地使用 ValueTask
都能让我们的程序运行得更加流畅。
不过要注意的是,不要多次 await 同一个 ValueTask,这会带来灾难性的后果,比如:
ValueTask<int> vt = GetDataOptimizedAsync();
int result1 = await vt; // 第一次 await 没问题
int result2 = await vt; // 这里会抛出异常
如果需要多次使用,先转换为Task,如:
Task<int> task = vt.AsTask();
int result1 = await task;
int result2 = await task; // 现在安全了
好了,今天的分享就到这里啦。
该文章在 2025/6/26 18:54:01 编辑过