通过 ValueTask 可以用来提升软件整体的性能,使用方法也非常简单,本文将带大家简单的入门使用这个 ValueTask 的功能 为什么使用 ValueTask 可以用来提升软件整体的性能? 回答这个文件的博客有很多,请看以下这几篇博客 深入理解 ValueTask - 沉睡的木木夕 - 博客园 如何使用 C# 中的 ValueTask - 技术译民 - 博客园 简单的使用方法就是在方法的返回值里面 另外,在考虑使用 ValueTask 之前,还是需要进行一定的性能分析。 在使用之后,依然需要做一些测试 在 .NET Framework 里面暂时还没有加入 ValueTask 的支持,因为 ValueTask 需要最低是 .NET Standard 2.1 才能支持,因此需要加上一点兼容的代码 可以用来兼容旧版本,如 .NET Framework 4.5 等,让这些能支持 ValueTask 的功能。
值 规则 ID CA2012 类别 可靠性 修复是中断修复还是非中断修复 非中断 原因 从成员调用中返回的 ValueTask 实例的使用方式可能导致异常、损坏或性能不佳。 规则说明 从成员调用中返回的 ValueTask 实例旨在直接等待。 多次尝试使用 ValueTask 或在已知完成之前直接访问其结果可能会导致异常或损坏。 忽略此类 ValueTask 可能指示出现功能 Bug,还可能降低性能。 如何解决冲突 通常情况下,应直接等待 ValueTask,而不是将其丢弃或存储到其他位置(如局部变量或字段)。 何时禁止显示警告 对于从任意成员调用返回的 ValueTask,调用方需要假设 ValueTask 必须使用一次(例如等待)并且仅使用一次。 但是,如果开发人员还控制被调用的成员并对其实现情况有全面了解,则开发人员可能知道可禁止显示警告,例如,如果返回 ValueTask 始终包装 Task 对象。 另请参阅 可靠性规则
六、ValueTask的有效消费模式 从表面上看,ValueTask和ValueTask<TResult>的使用限制要比Task和Task<TResult>大得多 。 通常,以下操作绝对不能用在ValueTask/ValueTask<TResult>上: await ValueTask/ValueTask<TResult>多次。 并且,在之后的代码中您再也不应该与该ValueTask/ValueTask<TResult>进行交互。 七、新异步API都应返回ValueTask/ValueTask<TResult>吗? 八、ValueTask和ValueTask<TResult>的下一步是什么?
六、ValueTask的有效消费模式 从表面上看,ValueTask和ValueTask<TResult>的使用限制要比Task和Task<TResult>大得多 。 通常,以下操作绝对不能用在ValueTask/ValueTask<TResult>上: await ValueTask/ValueTask<TResult>多次。 并且,在之后的代码中您再也不应该与该ValueTask/ValueTask<TResult>进行交互。 七、新异步API都应返回ValueTask/ValueTask<TResult>吗? 八、ValueTask和ValueTask<TResult>的下一步是什么?
开始飙车 回到本篇文章的主题,ValueTask。 public readonly struct ValueTask : IEquatable<ValueTask> { } 是的,它就是这个样子。它是一个结构体,也就是值类型。 ValueTask 被讲的这么好,是不是所有用Task的地方都可以用ValueTask了呢? 因为是包装的原因,所以您可将所有用Task的地方转换为ValueTask,编译器并不会报错,而且ValueTask还可以转换为Task,毕竟是个包装器嘛。 来看看ValueTask的源码: ? ? 所以如果异步操作需要返回Task的情况下,我们将返回值更改为ValueTask反而增大了内存存储量(有一个Task对象,又有一个ValueTask对象)。 那么?
ValueTask作为.NET 引入的一个重要类型,为优化异步性能提供了轻量级的解决方案。深入理解ValueTask的原理、适用场景及使用技巧,对构建高性能的.NET 应用至关重要。 使用ValueTask优化整个异步过程。 ValueTask<int> valueTask = new ValueTask<int>(Task.Run(() => { int sum = ValueTask可以通过AsTask方法转换为Task,这在需要将ValueTask传递给期望Task类型的方法时很有用。 反之,Task可以作为参数传递给ValueTask的构造函数,将其包装为ValueTask。 2. ValueTask在异步流(IAsyncEnumerable)中如何使用?
什么是ValueTask? ValueTask是.NET引入的轻量级Task替代方案,适用于预期快速完成或可能同步完成的异步操作。 使用注意事项 ValueTask的正确使用 • 避免多次等待: // 错误用法 ValueTask<int> valueTask = GetCachedValueAsync("key"); int value1 = await valueTask; int value2 = await valueTask; // 运行时错误! • 兼容性:多数.NET库基于Task设计,ValueTask可能引入适配成本。 推荐策略: • 通用场景:默认使用Task。 • 高性能优化:在特定场景(如缓存、高频调用)使用ValueTask。 掌握Task与ValueTask的选择技巧,可显著提升应用性能与资源效率。在追求极致性能的代码路径中,合理使用ValueTask,让内存分配最小化,响应速度最大化!
目录 1,可用版本与参考资料 2,ValueTask 和 Task 3,编译器如何编译 4,ValueTask 有什么优势 5,ValueTask 创建异步任务 6,IValueTaskSource 和自定义包装 ValueTask/ValueTask<TResult> 出现时间其实比较早的了,之前一直没有深入,借此机会好好学习一番。 ,以下版本的 .NET 程序(集)可以使用 ValueTask/ValueTask<TResult>。 5,ValueTask 创建异步任务 我们看一下 ValueTask 和 ValueTask<TResult> 的构造函数定义。 所以,需要使用 Task 转换为 ValueTask: public ValueTask(Task task); // ValueTask 构造函数 ValueTask 只是包装 Task 的返回结果
; public ValueTask<object? (actionResult); } // ValueTask if (result is ValueTask valueTask) { > ConvertFromValueTask<T>(ValueTask<T> valueTask) { var result = valueTask.IsCompleted ? ; } private static async ValueTask<IActionResult> Convert(ValueTask valueTask) { >; ValueTask<IActionResult>:直接返回; 实现了IActionResult接口:根据该对象创建ValueTask<IActionResult>; ValueTask:调用Convert
no.StartsWith("NO")) { return new ValueTask<object?>("no is error!") no.StartsWith("NO")) { return new ValueTask<object?>("no is error!") no.StartsWith("NO")) { return new ValueTask<object?>("no is error!") GetData).AddFilter<MyFilter>(); app.Run(); public class MyFilter : IRouteHandlerFilter { public ValueTask no.StartsWith("NO")) { return new ValueTask<object?>("no is error!")
Abort(); public abstract void Abort(ConnectionAbortedException abortReason); public virtual ValueTask public interface IConnectionListener : IAsyncDisposable { EndPoint EndPoint { get; } ValueTask > AcceptAsync(CancellationToken cancellationToken = default(CancellationToken)); ValueTask UnbindAsync features = null,CancellationToken cancellationToken = default(CancellationToken)); ValueTask UnbindAsync public interface IConnectionListenerFactory { ValueTask<IConnectionListener> BindAsync(EndPoint endpoint
<bool> MoveNextAsync(); T Current { get; } ValueTask DisposeAsync(); } 代码示例 基础用法 using System <bool>(index < data.Count); } public int Current => data[index]; public ValueTask // 错误示例 public ValueTask<bool> MoveNextAsync() { // 没有检查取消令牌 index++; return new ValueTask public ValueTask<bool> MoveNextAsync() { cancellationToken.ThrowIfCancellationRequested(); index ++; return new ValueTask<bool>(index < data.Count); } 性能对比/实践建议 与同步迭代相比,IAsyncEnumerable<T>在处理异步操作时性能优势明显
如果Action方法的返回值是一个Task<TResult>或者ValueTask<TResult>对象,它们的Result属性返回的参数这个待转换的数据对象。 如代码片段所示,我们在FoobarController类型中定义了四个Action方法,它们返回的类型分别为Task<ContentResult>、ValueTask<ContentResult>、Task <String>、ValueTask<String>,ContentResult对象的内容和直接返回的字符串都是一段相同的HTML。 <ContentResult> BarAsync() => new ValueTask<ContentResult>(new ContentResult(_html, "text/html")) <string> QuxAsync() => new ValueTask<string>(_html); } 我们在上述四个Action方法上通过标注HttpGetAttribute特性将路由模板分别设置为
public static ValueTask<Point? TryParse(expression, out var point)) { result = point; } return new ValueTask public interface IBindable<T> { abstract static ValueTask<T? var y)) return false; result = new Point(x, y); return true; } public static ValueTask TryParse(expression, out var point)) { result = point; } return new ValueTask
} }); ️ 使用拦截器自定义日志 public classCustomLoggingInterceptor : IHttpLoggingInterceptor { public ValueTask // 添加追踪ID context.AddParameter("RequestId", Guid.NewGuid().ToString()); return ValueTask.CompletedTask ; } public ValueTask OnResponseAsync(HttpLoggingInterceptorContext context) { // Set-Cookie等敏感Header context.HttpContext.Response.Headers.Remove("Set-Cookie"); return ValueTask.CompletedTask 保护隐私是赢得用户信任的基础 解决方案: public classSensitiveDataRedactionInterceptor : IHttpLoggingInterceptor { public ValueTask
cancellationToken.IsCancellationRequested) { // 执行操作 } } 缓存返回值:ValueTask<T>的优势 在频繁调用的异步方法中 ,使用ValueTask<T>作为返回类型可以提高性能。 ValueTask<T>是一个值类型,它避免了不必要的内存分配,特别是在高性能场景下。 public ValueTask<int> GetCountAsync() { int count = 0; // 计算count的值 return new ValueTask<
过度使用Task而不是ValueTask 问题: 对于经常同步返回的方法使用Task可能导致不必要的堆分配,影响性能。 使用ValueTask时:方法GetDataWithValueTask使用ValueTask,对于同步完成的情况可避免堆分配。经过的时间将针对相同数量的迭代进行测量。 结论: 对于经常同步返回的方法,使用ValueTask替代Task可以减少内存开销并提高性能。 Elapsed time with Task: 1500 ms Starting with ValueTask... Elapsed time with ValueTask: 1200 ms 在这个示例中,与使用Task相比,使用ValueTask带来了显著的性能提升。 其他最佳实践 6.
异步流实现 在底层,IAsyncEnumerable的实现通常依赖于异步操作,如Task和ValueTask。 例如,MoveNextAsync方法可能会返回一个ValueTask<bool>,用于优化短暂的异步操作。同时,它会利用await关键字暂停和恢复异步操作,确保在等待数据时不会阻塞线程。 DisposeAsync() { return default; } public async ValueTask<bool> DisposeAsync() { return default; } public async ValueTask<bool> 异步操作优化:在MoveNextAsync方法中,尽量使用高效的异步操作,如ValueTask代替Task,以减少不必要的开销。 错误处理:在异步迭代过程中,要正确处理可能出现的异常。
RegisterLocationChangingHandler()方法,该方法定义如下: RegisterLocationChangingHandler(Func<LocationChangingContext, ValueTask > locationChangingHandler) 传入一个Func<LocationChangingContext,ValueTask> locationChangingHandler 类型的委托 NavigationManager.RegisterLocationChangingHandler(OnLocationChanging); } } private ValueTask Console.WriteLine($"IsNavigationIntercepted:{context.IsNavigationIntercepted}"); return ValueTask.CompletedTask 需要手动在实现的 Dispose()方法中释放资源 点击代码跳转 点击链接跳转 拦截跳转 拦截跳转我们可以使用context.PreventNavigation()方法进行拦截 private ValueTask
下面我们看这个ValueTask等待类型(结构),相对于Task类来说,ValueTask没有堆中对象的开销。 这种情况ValueTask就变得很适用了。我们看下面这个案例,使用ValueTask时,在五秒内的情况下直接从它的构造函数返回值。如果时间不在五秒内的话就使用真正获取数据的方法。 if (_time >= DateTime.Now.AddSeconds(-5)) { return await new ValueTask Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); Console.WriteLine("ValueTask 我们看其运行结果,使用Task和ValueTask的运行结果耗时相差是巨大的。所以在一些特殊情况下使用ValueTask或许会更加的适用。 总结 今天我们介绍了关于任务相关的一些知识概念。