展会邀请函在哪个网站做,游戏软件制作开发,福州开发公司,网站icp备案号概要
我们在开发过程中#xff0c;经常使用async的异步方法#xff0c;但是有些时候#xff0c;异步的方法中#xff0c;可能包含一些同步的处理。本文主要介绍通过ValueTask这个struct#xff0c;优化异步处理的方法性能。
代码及实现
有些时候我们会缓存一些数据在内…概要
我们在开发过程中经常使用async的异步方法但是有些时候异步的方法中可能包含一些同步的处理。本文主要介绍通过ValueTask这个struct优化异步处理的方法性能。
代码及实现
有些时候我们会缓存一些数据在内存中这些数据因为不经常改变所以并不需要每次都要从后台数据库中获取。
例如下面的代码 private static ListBranch _branches;public async TaskListBranch getBranches(){if (_branches is null){using (var context new BankContext()){_branches await context.Branches.ToListAsync();} }return _branches;
}在一个银行App相关的系统中我们将分行的基本信息缓存在内存中方便其它方法调用。
上面的代码有一个问题无论我们的缓存是否命中都会以TaskList的形式返回。也就是说Runtime需要为返回Task相关的内容分配内存空间如果缓存命中意味着该方法仅仅是执行同步操作实际上只是一个同步操作。
如果以TaskList作为返回值对于同步操作而言完全是在浪费系统资源。Task是一个类这就意味着只要我们要使用该类就必须创建对象然后在通过GC收集。
对于一些高吞吐量高并发的站点如果可以对其进行适当优化可以节约大量资源。
ValueTask 解决方法
在.Net Core .2.0中引入一个结构体类型 ValueTask, 用于处理async方法中同步和异步返回并存的情况。
因为其只是一个结构体它并不需要像Task那样去创建对象再被GC收集。但是它却可以包裹TResult或Task作为async方法的返回值。
我们将上面的代码进行修改将Task替换成ValueTask即可
private static ListBranch _branches;
public async ValueTaskListBranch getBranchesByTaskValue(){if (_branches is null){using (var context new BankContext()){_branches await context.Branches.ToListAsync();return _branches;} }return _branches;
}我们用Benchmark测试上述两个方法的性能。
从测试结果上看ValueTask作为返回值消耗时间增加了约27%但是内存消耗几乎可以忽略不计。
全部代码请参考附录
附录
Programs.cs
using System.Diagnostics;
using System.Globalization;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Net.Mail;
using System.ComponentModel.Design.Serialization;
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using System.Linq;
using System.Collections.Generic;
using BenchmarkDotNet.Running;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Diagnosers;
namespace IQueryableIEnumerable
{[MemoryDiagnoser]public class Programs{[Benchmark]public async Task getBranches(){TaskValueTest task new TaskValueTest();for(var i0;i5;i){await task.getBranches();}}[Benchmark]public async Task getBranchesByValueTask(){TaskValueTest task new TaskValueTest();for(var i0;i5;i){await task.getBranchesByTaskValue();}}public static void Main(string[] args){var summary BenchmarkRunner.RunPrograms(); } }
}
TaskValueTest.cs
namespace IQueryableIEnumerable
{using System;using System.Threading;using System.Threading.Tasks;using Microsoft.EntityFrameworkCore;using System.Linq;using System.Collections.Generic;using BenchmarkDotNet.Running;using BenchmarkDotNet.Attributes;using BenchmarkDotNet.Diagnosers;public class TaskValueTest{private static ListBranch _branches;private static ListBranch _branches2;public async ValueTaskListBranch getBranchesByTaskValue(){if (_branches is null){using (var context new BankContext()){_branches await context.Branches.ToListAsync();} }return _branches;}public async TaskListBranch getBranches(){if (_branches2 is null){using (var context new BankContext()){_branches2 await context.Branches.ToListAsync();} }return _branches2;}}
}