当前位置: 首页 > ds >正文

ValueTask 实战指南:解锁 .NET 异步编程的性能秘密

简介

ValueTask.NET Core 2.0+ 引入的高性能异步操作类型,用于优化可能同步完成的异步操作,减少内存分配和性能开销。

为什么需要 ValueTask?

Task 的性能问题
  • 堆分配开销:每次创建 Task<T> 都会在堆上分配对象(约 1KB),高频调用会导致 GC 压力。

  • 多数场景同步完成:许多异步方法在多数情况下可以直接返回结果,无需真正异步。

ValueTask 的优势
  • 值类型:ValueTask<T>struct,避免堆分配。

  • 双重表示:

    • 直接存储同步结果(无需分配)。

    • 包装真正的 Task<T>(当确实需要异步时)。

ValueTask本质
public readonly struct ValueTask<TResult> : IEquatable<ValueTask<TResult>>
{private readonly object? _obj; // Task或IValueTaskSourceprivate readonly TResult _result; // 同步结果private readonly short _token; // 验证令牌// ...
}

典型使用场景

  • 同步完成概率高

    • 缓存命中、预加载数据、简单计算等。

    • 示例:从缓存读取数据,命中时同步返回。

  • 高频调用的异步方法

    • 如网络库、序列化、中间件等底层组件。

    • 避免大量 Task 分配导致的 GC 压力。

  • 热路径(Hot Path)优化

    • 性能关键的代码段(如循环内调用)。

核心使用场景

高频调用且多数情况同步完成的方法
// 缓存场景:多数情况直接命中缓存(同步)
public ValueTask<string> GetDataAsync(string key)
{if (_cache.TryGetValue(key, out string value)){return new ValueTask<string>(value); // 同步返回,无堆分配}return new ValueTask<string>(LoadDataFromDbAsync(key)); // 异步返回
}
实现异步接口或基类方法
// 实现异步接口时,优先使用 ValueTask
public interface IDataProvider
{ValueTask<string> GetDataAsync(string key);
}
异步流中的值返回
// 异步流中的值生成
public async IAsyncEnumerable<ValueTask<int>> GenerateValuesAsync()
{for (int i = 0; i < 10; i++){await Task.Delay(100);yield return new ValueTask<int>(i); // 高效返回值}
}

详细用法与示例

创建 ValueTask
// 同步结果(无堆分配)
ValueTask<int> GetSynchronizedResult()
{return new ValueTask<int>(42); // 直接存储结果
}// 异步结果(包装 Task)
ValueTask<int> GetAsynchronizedResult()
{return new ValueTask<int>(Task.Delay(100).ContinueWith(_ => 42));
}
消费 ValueTask
// 推荐方式:直接 await
await foreach (var valueTask in GenerateValuesAsync())
{int value = await valueTask; // 安全消费,支持同步/异步场景
}// 手动检查(不常用)
async Task ConsumeValueTask(ValueTask<int> valueTask)
{if (valueTask.IsCompletedSuccessfully){int value = valueTask.Result; // 直接获取结果(无等待)}else{int value = await valueTask; // 等待异步完成}
}
与 Task 的转换
// 转换为 Task(需谨慎,会导致堆分配)
Task<int> task = valueTask.AsTask();// 从 Task 创建 ValueTask
ValueTask<int> valueTask = new ValueTask<int>(Task.FromResult(42));
混合同步/异步完成
public ValueTask<string> ReadDataAsync()
{if (_buffer.Length > 0)return new ValueTask<string>(_buffer.ToString()); // 同步return new ValueTask<string>(ReadFromStreamAsync()); // 异步
}
使用 async 方法(.NET Core 3.0+)
public async ValueTask<byte[]> ComputeHashAsync(byte[] data)
{if (data.Length < 1024)return ComputeHashSync(data); // 同步分支return await Task.Run(() => ComputeHash(data)); // 异步分支
}private byte[] ComputeHashSync(byte[] data) { ... }

高级模式:IValueTaskSource

对象池集成(极致优化)
private static readonly ObjectPool<MyValueTaskSource> _pool = new DefaultObjectPool<MyValueTaskSource>(new PooledPolicy());public ValueTask<int> GetOptimizedValueAsync()
{var source = _pool.Get();try{if (source.TrySetResultIfPossible(42))return new ValueTask<int>(source, source.Version);StartAsyncOperation(source);return new ValueTask<int>(source, source.Version);}catch{_pool.Return(source);throw;}
}private void StartAsyncOperation(MyValueTaskSource source)
{ThreadPool.UnsafeQueueUserWorkItem(state =>{try{// 模拟工作Thread.Sleep(10);source.SetResult(42);}finally{_pool.Return(source);}}, null);
}
自定义ValueTaskSource完整实现
public class MyValueTaskSource : IValueTaskSource<int>
{private ManualResetValueTaskSourceCore<int> _core;public int GetResult(short token) => _core.GetResult(token);public ValueTaskSourceStatus GetStatus(short token) => _core.GetStatus(token);public void OnCompleted(Action<object?> continuation, object? state, short token, ValueTaskSourceOnCompletedFlags flags)=> _core.OnCompleted(continuation, state, token, flags);public void SetResult(int result) => _core.SetResult(result);public void SetException(Exception error) => _core.SetException(error);// 版本令牌防重用public short Version => _core.Version;
}

注意事项

禁止多次 await 同一个 ValueTask

ValueTask 不保存状态,多次 await 可能导致异常或未定义行为。

var task = GetValueTask();
await task; // OK
await task; // ❌ 错误!ValueTask 只能消费一次
需要多次消费时转换为 Task
Task<int> task = GetValueTask().AsTask();
await task;
await task; // 安全(但通常应避免多次 await)
避免在异步方法外阻塞
// ❌ 危险!可能导致死锁
var result = GetValueTask().Result;// ✅ 推荐做法
var result = await GetValueTask();

何时避免使用 ValueTask

  • 方法总是异步完成 → 用 Task

  • 需要多次 await 或长期存储任务结果 → 用 Task

  • 不关心性能的普通场景 → 优先 Task(代码更简单)。

底层原理

  • 同步完成:内联存储结果(TResult),零分配。

  • 异步完成:内部包装一个 Task 或实现 IValueTaskSource.NET Core 3.0+),分配一次对象。

  • IValueTaskSource:高级场景下手动管理异步状态(如 Socket、PipeReader)。

最佳实践总结

场景推荐类型原因
可能同步完成的高频方法ValueTask减少分配
总是异步完成Task避免 ValueTask 额外开销
需存储任务或多次 awaitTaskValueTask 不支持复用
库/框架开发(性能敏感)ValueTask最大化调用方性能

性能基准对比

方法内存分配GC 触发执行时间
Task.FromResult48 MBGen0: 15650 ms
ValueTask.FromResult0 MB0120 ms
IValueTaskSource+池0.01 MB095 ms

决策流程:何时使用ValueTask

在这里插入图片描述

http://www.xdnf.cn/news/18893.html

相关文章:

  • window显示驱动开发—混合系统 DDI 和 dList DLL 支持
  • 【P2P】P2P主要技术及RELAY服务实现
  • mac设置鼠标滚轮方向
  • 让清洁更智能,让城市更美好
  • 20、DMA----释放CPU压力,加快传输
  • 无人机航拍数据集|第30期 无人机腰果成熟度目标检测YOLO数据集3098张yolov11/yolov8/yolov5可训练
  • Day8--HOT100--160. 相交链表,206. 反转链表,234. 回文链表,876. 链表的中间结点
  • 艾利特石油管道巡检机器人:工业安全的智能守护者
  • 高通平台wifi--p2p issue
  • leetcode 17.04 消失的数字
  • 理解Vuex的辅助函数,分析mapState、mapGetters、mapMutations和mapActions各个应用场景
  • SQL 语句拼接在 C 语言中的实现与安全性分析
  • 大模型应用实战:构建企业知识库 RAG 系统(含权限控制 + 多轮对话)
  • 无线USB转换器TOS-WLink网盘更新--TOS-WLink使用帮助V1.0.pdf
  • 【C++游记】List的使用和模拟实现
  • 矩阵系统源代码开发,支持OEM贴牌
  • 5G与6G技术演进与创新对比分析
  • 我们为你连接网络,安装驱动程序
  • 车载诊断架构 --- DTC Event与DTC Status的对应关系
  • AWS ECS 成本优化完整指南:从分析到实施的最佳实践
  • CVPR 2025端到端自动驾驶新进展:截断扩散模型+历史轨迹预测实现精准规划
  • Frida 加密解密算法实现与应用指南
  • 【Linux】协议的本质
  • 基于深度学习的翻拍照片去摩尔纹在线系统设计与实现
  • Java基础第4天总结(继承)
  • 小明的Java面试奇遇之发票系统相关深度实战挑战
  • 论文阅读:VACE: All-in-One Video Creation and Editing
  • 纯净Win11游戏系统|24H2专业工作站版,预装运行库,无捆绑,开机快,游戏兼容性超强!
  • Linux应急响应一般思路(二)
  • 【Docker基础】Docker-compose多容器协作案例示例:从LNMP到分布式应用集群