.NET 6 数组拷贝性能对比

本文来对比多个不同的方法进行数组拷贝,和测试其性能

测试性能必须采用基准(标准)性能测试方法,否则测试结果不可信。在 dotnet 里面,可以采用 BenchmarkDotNet 进行性能测试。详细请看 C# 标准性能测试

拷贝某个数组的从某个起始点加上某个长度的数据到另一个数组里面,可选方法有很多,本文仅列举出使用 for 循环拷贝,和使用 Array.Copy 方法和用 Span 方法进行拷贝进行对比

假定有需要被拷贝的数组是 TestData 其定义如下

static Program(){TestData = new int[1000];for (int i = 0; i < 1000; i++){TestData[i] = i;}}private static readonly int[] TestData;

使用 for 循环拷贝的方法如下

public object CopyByFor(int start, int length){var rawPacketData = TestData;var data = new int[length];for (int localIndex = 0, rawArrayIndex = start; localIndex < data.Length; localIndex++, rawArrayIndex++){data[localIndex] = rawPacketData[rawArrayIndex];}return data;}

以上代码返回 data 作为 object 仅仅只是为了做性能测试,避免被 dotnet 优化掉

另一个拷贝数组是采用 Array.Copy 拷贝,逻辑如下

public object CopyByArray(int start, int length){var rawPacketData = TestData;var data = new int[length];Array.Copy(rawPacketData,start,data,0, length);return data;}

采用新的 dotnet 提供的 Span 进行拷贝,代码如下

public object CopyBySpan(int start, int length){var rawPacketData = TestData;var rawArrayStartIndex = start;var data = rawPacketData.AsSpan(rawArrayStartIndex, length).ToArray();return data;}

接着加上一些性能调试辅助逻辑

[Benchmark][ArgumentsSource(nameof(ProvideArguments))]public object CopyByFor(int start, int length){var rawPacketData = TestData;var data = new int[length];for (int localIndex = 0, rawArrayIndex = start; localIndex < data.Length; localIndex++, rawArrayIndex++){data[localIndex] = rawPacketData[rawArrayIndex];}return data;}[Benchmark][ArgumentsSource(nameof(ProvideArguments))]public object CopyByArray(int start, int length){var rawPacketData = TestData;var data = new int[length];Array.Copy(rawPacketData,start,data,0, length);return data;}public IEnumerable<object[]> ProvideArguments(){foreach (var start in new[] { 0, 10, 100 }){foreach (var length in new[] { 10, 20, 100 }){yield return new object[] { start, length };}}}

在我的设备上的测试效果如下

BenchmarkDotNet=v0.13.1, OS=Windows 10.0.19042.1200 (20H2/October2020Update)
Intel Core i7-9700K CPU 3.60GHz (Coffee Lake), 1 CPU, 8 logical and 8 physical cores
.NET SDK=6.0.100-preview.7.21379.14[Host]     : .NET 6.0.0 (6.0.21.37719), X64 RyuJITDefaultJob : .NET 6.0.0 (6.0.21.37719), X64 RyuJIT

b3728c4acf7c520091c9a7dd0640d190.png

可以看到,在对比使用 for 循环拷贝和使用 Array.Copy 拷贝中,使用 Array.Copy 拷贝的性能更好,在拷贝的数组长度越长的时候,使用 Array.Copy 拷贝性能优势就更好

接下来再加上 Span 的性能比较,如下面代码

[Benchmark][ArgumentsSource(nameof(ProvideArguments))]public object CopyBySpan(int start, int length){var rawPacketData = TestData;var rawArrayStartIndex = start;var data = rawPacketData.AsSpan(rawArrayStartIndex, length).ToArray();return data;}

性能对比测试如下

c6bdbbed2c2fbdb241c6eb51f2e71665.png

可以看到 Span 的性能比 Array.Copy 拷贝性能更强

在 Span 里面,转换为数组的逻辑如下

[MethodImpl(MethodImplOptions.AggressiveInlining)]public T[] ToArray(){if (_length == 0)return Array.Empty<t>();var destination = new T[_length];Buffer.Memmove(ref MemoryMarshal.GetArrayDataReference(destination), ref _pointer.Value, (nuint)_length);return destination;}

这里使用到的 Buffer 的有黑科技的 Memmove 方法,此方法的实现如下

[MethodImpl(MethodImplOptions.AggressiveInlining)]internal static void Memmove<t>(ref T destination, ref T source, nuint elementCount){if (!RuntimeHelpers.IsReferenceOrContainsReferences<t>()){// Blittable memmoveMemmove(ref Unsafe.As<t, byte="">(ref destination),ref Unsafe.As<t, byte="">(ref source),elementCount * (nuint)Unsafe.SizeOf<t>());}else{// Non-blittable memmoveBulkMoveWithWriteBarrier(ref Unsafe.As<t, byte="">(ref destination),ref Unsafe.As<t, byte="">(ref source),elementCount * (nuint)Unsafe.SizeOf<t>());}}

以上性能测试使用的是 int 数组,刚好能进入 Memmove 的分支,而不是 BulkMoveWithWriteBarrier 这个分支。在里层的 Memmove 方法里面用到了很多黑科技,本文只是用来对比多个方法拷贝数组的性能,黑科技部分就需要大家自己去阅读 dotnet 的源代码啦

另外,如果需要做完全的数组的拷贝,数组里面存放的是值类型对象,如 int 类型,那么拷贝整个数组还有另一个可选项是通过 Clone 方法进行拷贝,代码如下

public object CopyByClone(){var data = (int[]) TestData.Clone();return data;}

使用 Clone 的方法的行为是返回数组的浅表拷贝,也就是说数组里面的元素没有做深拷贝,只是拷贝数组本身而已。对于值类型来说,就没有啥问题了

稍微更改一下性能测试,更改的代码如下

[MemoryDiagnoser]public class Program{static void Main(string[] args){BenchmarkRunner.Run<program>();}static Program(){TestData = new int[1000];for (int i = 0; i < 1000; i++){TestData[i] = i;}}[Benchmark]public object CopyByFor(){var rawPacketData = TestData;var length = TestData.Length;var data = new int[length];for (int localIndex = 0, rawArrayIndex = 0; localIndex < data.Length; localIndex++, rawArrayIndex++){data[localIndex] = rawPacketData[rawArrayIndex];}return data;}[Benchmark]public object CopyByArray(){var length = TestData.Length;var start = 0;var rawPacketData = TestData;var data = new int[length];Array.Copy(rawPacketData,start,data,0, length);return data;}[Benchmark]public object CopyByClone(){var data = (int[]) TestData.Clone();return data;}private static readonly int[] TestData;}

通过下图可以了解到采用 Clone 方法和采用 Array.Copy 方法的性能差不多,但 Clone 稍微快一点

7fbb24b1386b7d3879f517bed3f87684.png

以上是给 WPF 框架做性能优化时测试的,详细请看

  • Using Array.Copy to make array copy faster in StylusPointCollection by lindexi · Pull Request #5217 · dotnet/wpf

  • Using the Clone method to fast clone the array in StylusPoint by lindexi · Pull Request #5218 · dotnet/wpf

特别感谢ThomasGoulet73大佬教我使用 AsSpan 的方法拷贝数组

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/297671.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python win32ui选取文件夹_最全 Python 算法实现资源汇总!

整理 | Rachel责编 | Jane出品 | Python大本营(ID&#xff1a;pythonnews)【导语】数据结构与算法是所有人都要学习的基础课程&#xff0c;自己写算法的过程可以帮助我们更好地理解算法思路&#xff0c;不要轻视每一个算法&#xff0c;一些虽然看似容易&#xff0c;但可能有很多…

兄弟,就你这智商就别出轨了吧?

1 这智商就别出轨了吧&#xff08;没有聪明人就能出轨的意思&#xff09;▼2 “俗话说得好”上一句是什么&#xff1f;▼3 这是什么诡异的老年运动&#xff1f;▼4 搞不懂时尚趋势在哪里.....▼5 聚餐的时候千万别拿着包去厕所▼6 一看就会一学就废▼7 聪明的狗子能有多…

requestmapping注解访问404_【框架】127:几个非常重要的注解

今天是刘小爱自学Java的第127天。感谢你的观看&#xff0c;谢谢你。今天的知识点有点多&#xff0c;有点记不过来了。学习内容安排如下&#xff1a;使用注解优化昨天写的springMVC入门程序。映射路径各种风格的学习&#xff0c;也就对应了注解RequestMapping中的参数。各种类型…

Dapr + .NET Core实战(二) 服务调用

服务调用是什么在分布式应用程序中的服务之间进行调用会涉及到许多挑战。例如&#xff1a;维护其他服务的地址。如何安全地调用服务。在发生短暂的 暂时性错误 时如何处理重试。分布式应用程序调用链路追踪。服务调用构建块通过使用 Dapr 挎斗作为服务的 反向代理 来解决这些难…

第五周项目2-对象作为数据成员

回想Engineer类的数据成员&#xff0c;有眼镜、背包等。某Engineer的眼镜、背包&#xff0c;是Glass、Bag类的对象。类中的数据成员&#xff0c;其类型可以是简单类型&#xff0c;也可以是类。通过这种方式&#xff0c;将某些类组合到另外的类中&#xff0c;当作其中的一个“部…

谷歌排名第一的编程语言,死磕它这两点,小白也能学的会!不信你看!

全世界只有3.14 % 的人关注了爆炸吧知识谷歌排名第一的编程语言时什么&#xff1f;毫无疑问&#xff1a;肯定是 Python。也难怪&#xff0c;作为大数据时代和人工智能时代的必备语言&#xff0c;Python 的优点太多了&#xff0c;语言简洁、易学、开发效率高、可移植性强......另…

android主动显示流程,Activity加载显示基本流程

本文章是基于Android源码6.0讲解Activity加载显示基本流程首先上一张图给大家一个直观的了解首先一个布局页面的加载是在Activity中的setContentView(R.layout.res)开始;我们就从Acitvity源码中的setContentView方法入手public void setContentView(LayoutRes int layoutResID)…

VIM之Project 项目管理工具

VIM是Linux和Unix下常用的文本编辑工具&#xff0c;在编写代码和阅读代码中经常使用。但VIM进行代码项目管理时&#xff0c;没有IDE集成开发工具方便&#xff0c;现在提供一个VIM插件Project&#xff0c;可以对代码项目进行简单的集中管理一、 下载安装1、 在 Vim 网站上下载最…

WPF DataGrid 通过自定义表头模拟首行固定

WPF DataGrid 通过自定义表头模拟首行固定独立观察员 2021 年 9 月 25 日最近工作中要在 WPF 中做个表格&#xff0c;自然首选就是 DataGrid 控件了。问题是&#xff0c;UI 设计的表格是在首行有一个新增按钮&#xff0c;那一行样式和其它数据行是一样的&#xff0c;就在表头下…

python和C语言分别实现插入排序

python语言代码&#xff1a;代码1 defInsertSort(numbers,n):2 fori inrange(1,n):3 j i-14 tem numbers[i]5 whilenumbers[j]>tem andj>0:6 numbers[j1] numbers[j]7 j -18 else:9 numbers[j1] tem10 print"Onthe sort:",numbers11 12 a [9,8,7,6,5,4,3,2,1,0…

Windows用户安全小技巧

本文适用于具有管理员用户和标准用户的所有Windows系统&#xff0c;如Windows 2000以上的操作系统&#xff0c;UAC是Windows Vista以上版本的具有功能。新安装的Windows系统或者新购买的含有Windows系统计算机一开始都需要安装许多软件并需要设置较多的含有Windows安全或用户控…

从网恋到失恋只需要一秒...

1 原来放下一个人如此简单...▼2 而且到现在衣服都没找到▼3 这东西叫糖醋液&#xff0c;实验室比例是&#xff1a;糖&#xff1a;醋&#xff1a;酒&#xff1a;水1&#xff1a;2&#xff1a;3&#xff1a;4▼4 老师&#xff1a;这孩子真有原则▼5 呵&#xff0c;绝交吧▼…

大前端快闪:package.json文件知多少?

最近在公司某项目参与了一些前端工作&#xff0c;作为后端抠脚大汉&#xff0c;改点前端细节磕磕绊绊&#xff0c;改点大前端、工程化、HTTP交互倒也还能做到柳暗花明。于是打算用后端程序猿的视角记录一些{大前端}的知识快闪&#xff0c;也算是帮助读者构建完整的全栈技能体系…

大牛C++编程开发学习建议50条

2019独角兽企业重金招聘Python工程师标准>>> 每个从事C开发的朋友相信都能给后来者一些建议&#xff0c;但是真正为此进行大致总结的很少。本文就给出了网上流传的对C编程开发学习的50条建议&#xff0c;总结的还是相当不错的&#xff0c;编程学习者&#xff08;不仅…

html2canvas改成同步,html2canvas转为图片异步转同步问题(记录)

描述&#xff1a;最近使用html2canvas插件截取页面上指定dom为图片&#xff0c;然后将生成的图片替换页面上的dom后&#xff0c;将替换后的页面内容保存至数据库&#xff0c;结果保存的是保存前的页面&#xff0c;初步判定是html2canvas的异步执行造成的。参考了两篇博文&#…

杨辉再发声明:没有及时交流工作进展,深表歉意

全世界只有3.14 % 的人关注了爆炸吧知识pixabay.com编者按加州大学付向东教授实名举报中科院上海神经所杨辉事件在过去一周成为学术界讨论的热点话题。付向东称自己2018年在神经所做学术报告后&#xff0c;杨辉重复其实验却未告知并抢发文章。杨辉7月3日发表声明&#xff0c;称…

z变换公式表_如何使用标准正态分布表?

正态分布这个概念在统计学中很常见&#xff0c;在做与正态分布有关计算的时候经常会用到标准正态分布表。如果知道一个数值的标准分数即z-score&#xff0c;就可以非常便捷地在标准正态分布表中查到该标准分数对应的概率值。任何数值&#xff0c;只要符合正态分布的规律&#x…

.NET 6 中的 ConfigurationManager

.NET 6 中的 ConfigurationManagerIntro.NET 6 为了 Minimal API 引入了一些新东西&#xff0c;其中就包含了一个全新的配置对象 ConfigurationManager这并不是 .NET Framework 里的静态类 ConfigurationManager&#xff0c;而是 .NET Core 里的配置 Microsoft.Extensions.Conf…

60个高质量的CSS、XHTML网页布局模板下载

无论您下载和解剖预建模板是为了学习最新的CSS布局技术&#xff0c;或者下载的目的是为了易于编辑制作现成的独立网站&#xff0c;您都不应该仅限于免费且可用的一个拥有众多克隆版本、陈旧的且往往是枯燥的模板。网页设计的流行趋势和技术总是在千变万化&#xff0c;因此&…

总有人会偷看你的朋友圈

全世界只有3.14 % 的人关注了爆炸吧知识生活中&#xff0c;总是会有人在默默关注着你。你的朋友圈&#xff0c;常常有人来“偷偷”光顾&#xff0c;而这些细枝末节常常被我们忽视。 你不想让关心你的人失望&#xff0c;于是在朋友圈分享优质文章&#xff0c;希望你的快乐…