各种数组元素复制方式的性能比较

PHP大数组过滤元素、修改元素性能分析 在PHP开发过程中,数组是非常重要的数据结构,往往有一个操作就是对数组进行过滤,修改,以下是对数组元素进行过滤的几个方法进行分析。 数据源是长度为4592的数组,占用内存8.9MB,方法重复执行5000次。   结论:无论是对数组进行过滤,修改,使用引用的方式是最优的,主要原因在于内存操作次数少。array_filter和array_walk需要调用一次函数,所耗的时间会更长   过滤数... 阅读详情

原本这只是“字符串”话题的一个分支,不过后来我发现这个问题单独来看也有一定参考价值,也有一些问题值得讨论的地方,其中也有一些问题希望得到高手指点,最终打算把这个话题独立处理。话不多说,现在就来看看。

这个话题是“复制数组元素”,它最简单的情况也就是把源数组的所有元素,一一复制到等长目标数组中去。在.NET中,我们可以使用多种方法来实现这个效果:

  • 使用for语句一个个复制元素。
  • 使用数组的CopyTo方法复制元素。
  • 使用Array.Copy静态复制元素。
  • 使用Buffer.BlockCopy复制元素。

于是使用如下代码进行实验:

int length = 1000 * 1000;
var source = Enumerable.Repeat(100, length).ToArray();
var dest = new int[length];

int iteration = 1000;
CodeTimer.Initialize();

CodeTimer.Time("One by one", iteration, () =>
{
    for (int i = 0; i < length; i++) dest[i] = source[i];
});

CodeTimer.Time("Int32[].CopyTo", iteration, () =>
{
    source.CopyTo(dest, 0);
});

CodeTimer.Time("Array.Copy", iteration, () =>
{
    Array.Copy(source, dest, length);
});

CodeTimer.Time("Buffer.BlockCopy", iteration, () =>
{
    Buffer.BlockCopy(source, 0, dest, 0, length * 4);
});

运行结果如下(GC都是0,就省略了):

One by one
        Time Elapsed:   3,153ms
        CPU Cycles:     7,570,978,116

Int32[].CopyTo
        Time Elapsed:   2,933ms
        CPU Cycles:     7,056,050,496

Array.Copy
        Time Elapsed:   3,018ms
        CPU Cycles:     7,244,562,468

Buffer.BlockCopy
        Time Elapsed:   2,925ms
        CPU Cycles:     7,014,908,760

我们发现,每种方法的性能其实都差不多,多次运行后发现,除了第一种方法(一一复制)的性能每次都会略差一些外,其他三种方法基本总是不相上下,时有胜负(可能Array.Copy和Buffer.BlockCopy胜利次数略多一些)。这和我起初的想象又有不同。我一开始认为后三种方法应该有较大领先才对,而Buffer.BlockCopy应该性能最好。因为在进行元素一一复制的时候,需要进行大量的下标计算,而每次读取和写入的时候也会为了避免GC造成对象地址变动而进行一些“固定”操作。而Array.Copy和Buffer.BlockCopy两个静态方法都是外部调用,CLR应该会为它们进行性能优化才对。

不过猜测总是敌不过测试数据——有机会还是看看汇编吧,用.NET Reflector看不出个所以然来。

那么,我们在实际使用过程中,应该使用哪种方式呢?

一一复制的方式最为灵活,您可以正着来,反着来,跳着来,爱咋来咋来;而CopyTo的灵活性最差,因为它只能复制数组的全部元素(事实上,CopyTo方法是ICollection接口的一部分);Array.Copy静态方法的作用是把原数组中连续的一段,复制到目标数组中去,如果您不需要蹦蹦跳跳地前进,用Array.Copy是比较理想辅助函数。而最后一个Buffer.BlockCopy,它其实并不是在复制“元素”,它复制的是“字节”——因此,在上面的代码中,BlockCopy的最后一个参数为length * 4,这是因为一个32位整数占4个字节,其实我要复制的并非是length个元素,而是要复制length * 4个字节。

如下面的代码则是将一个长为100的int数组,复制到了长为100的long数组中去。此时,目标数组的每个元素为100L:

int length = 100;
var source = Enumerable.Repeat(10, length).ToArray();
var destLong = new long[length];
Array.Copy(source, destLong, length);

而下面的代码,是把长度100的int数组的所有字节,复制到长为50的long数组里去。由于是字节级别的填充,因此目标数组的每个元素是42949672970L:

var destLong = new long[length / 2];
Buffer.BlockCopy(source, 0, destLong, 0, length * 4);

那么将int(32位整数)数组复制到byte(8位)或short(16位)上会是什么结果呢?会不会受到字节序的影响,而造成不同平台上的结果差异呢?我猜,应该不会吧,CLR在平台差异性问题上解决的其实不错。那如果没有区别的话,CLR又是怎么处理这个情况的呢?我不清楚,似乎也没有什么条件来实验,还是请高手来指点吧。

那么,下面的代码又会是什么情况呢?objest数组的每个元素都指到哪儿去了呢?

var objs = new object[length];
Buffer.BlockCopy(source, 0, objs, 0, length * 4);

结果是“抛出异常”。因为Buffer.BlockCopy只能复制基础类型(primitive)的数组,不能复制引用,也不能复制各种复杂的struct类型。因此,其实Buffer.BlockCopy理论上不能算是一种“数组元素复制方式”。

补充测试(引用数组)

经RFX大牛提示,在引用复制时会为了避免GC造成影响而使用Write Barrier,因此使用引用类型进行测试会有明显的效果。于是我们来补充一个测试:

int length = 1000 * 1000;
var source = Enumerable.Repeat(new object(), length).ToArray();
var dest = new object[length];

int iteration = 1000;
CodeTimer.Initialize();

CodeTimer.Time("One by one", iteration, () =>
{
    for (int i = length - 1; i >= 0; i--) dest[i] = source[i];
});

CodeTimer.Time("Int32[].CopyTo", iteration, () =>
{
    source.CopyTo(dest, 0);
});

CodeTimer.Time("Array.Copy", iteration, () =>
{
    Array.Copy(source, dest, length);
});

结果如下:

One by one
        Time Elapsed:   7,298ms
        CPU Cycles:     17,523,631,872

Int32[].CopyTo
        Time Elapsed:   4,117ms
        CPU Cycles:     9,823,501,236

Array.Copy
        Time Elapsed:   4,225ms
        CPU Cycles:     10,119,239,496
28、Java数组操作与算法详解 本文详细介绍了Java中数组的基础操作与常用算法,包括数组复制、元素运算、数组作为方法参数、数组比较、求和、求平均值、查找最大值和最小值等。同时,文章还涵盖了数组的进阶应用,如排序、多维数组、搜索算法以及性能优化等内容。通过丰富的示例代码和实际应用案例,帮助读者深入理解和掌握Java数组的使用方法和技巧,从而更高效地处理数组数据并应用于实际开发中。 阅读详情

相关推荐

实现数组复制常用的5种方式及组合类的深复制(深拷贝)

在Java语言中,一般会采用下面的几种方法进行数组的复制。 a) for循环逐一复制; b) System.arraycopy()方法 c) Arrays.copyOf()方法 d) 使用clone()方法 e) Arrays.copyOfRange()方法 接下来,我们看下这几种方法的效率和源码,以及如何使用序列化和反序列化实现组合类的深复制。 我们以百万级和千万级的数据作为测试集。测试源码如下: public static void main(String[] args) throws CloneNotSupportedException { // int length = 1000

【JAVA】数组复制效率的比较

数组复制效率的比较 java中数组复制的方式,有以下几种 (1)System.arraycopy(); (2)Arrays.copyOf(); (3)clone(); (4)for循环 今天我们比较一下这四者的效率 一、System.arraycopy() 此方法的源码如下: public s...

阳阳的博客 1万+

YOLOv11多模态融合实战:基于YOLOFuse的RGB与红外线(IR)协同检测技术解析

本文深入解析了基于YOLOv11的YOLOFuse多模态融合技术,重点探讨了RGB与红外线(IR)协同检测的实现原理与实战应用。文章详细介绍了双流架构与数据级、特征级、决策级三种融合策略,并通过实战案例展示了其在低光照、复杂环境下显著提升检测精度与鲁棒性的优势,为全天候安防、自动驾驶等场景提供了有效的技术解决方案。

weixin_29041195的博客 650

C#数据结构-Array.Copy和Buffer.BlockCopy详解

通过对C#文档中Array.Copy()和Buffer.BlockCopy()两个方法的整理,深刻理解其运行原理及实现方式。在理解了Array.Copy()之后,从而对List<T>的拷贝、插入、删除操作实现,有一个更深入的理解。 一、Array.Copy的详细文档 从给定的索引开始复制数组中的一系列元素,将它们粘贴到另一数组中(从给定的开始复制的索引开始) ...

qq826364410的专栏 2万+

MySQL 分库分表及其平滑扩容方案

MyCAT不仅仅可以用作读写分离,以及分表分库、容灾管理,而且可以用于多租户应用开发、云平台基础设施,让你的架构具备很强的适应性和灵活性。分表对于一张多行(记录)多列(字段)的二维数据表,又分两种情形(1)垂直分表竖向切分,不同分表存储不同的字段,可以把不常用或者大容量、或者不同业务的字段拆分出去;扩容前每个节点的数据,有一半要迁移至一个新增节点中,对应关系比较简单。此时,四个节点的数据都已完整,只是有冗余(多存了和自己配对的节点的那部分数据),择机清除即可(过后随时进行,不影响业务)。...

m0_71777195的博客 1929

基于51单片机的多功能计算器全套设计

当今社会,随着人们物质生活的不断提高,电子产品已经走进了家家户户,无论是生活或学习,还是娱乐和消遣几乎样样都离不开电子产品,大型复杂的计算能力是人脑所不能胜任的,而且人脑比较容易出错。计算器作为一种快速通用的计算工具方便了用户的使用。计算器可谓是我们最亲密的电子伙伴之一。本设计着重在于分析计算器设计开发过程中的环节和步骤,并从实践经验出发对计算器设计做了详细的分析和研究。 本设计是以STC89C52单片机为核心的计算器模拟系统设计,输入采用5×8矩阵键盘,可以进行加、减、乘、除等十几种数字运算,同时支持括号

runweipa的博客 1743

数组拷贝的速度比较

#include iostream>#include time.h>#include stddef.h>#include string.h>using namespace std;void copy_with_pointers(char const *src,char *dst,size_t n)...{    for(size_t k=0;k!=n;++k)        *dst++=*s

下下签的专栏--璇玑玉衡 1292

从基础知识到PCB设计,打造全能硬件工程师

成为一名出色的硬件工程师需要在多个领域建立坚实的基础。从硬件基础知识、元器件学习、模拟电子电路到PCB设计,以及数字电子电路与通信,每个方面都是构建全面硬件工程师技能集的重要组成部分。通过深入学习和实践这些领域,你将能够在硬件工程领域中取得更多的成就。

weixin_46969363的博客 2724

Buffer.BlockCopy VS Array.Copy VS ConstrainedCopy

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_33979745的博客 306

YOLO模型在STM32微控制器上的部署:1.98M参数如何塞进嵌入式设备?

<think>我们根据内容生成不超过150字的摘要。内容主要是关于YOLO模型在STM32微控制器上的部署,包括STM32N6 NPU、模型量化、工具链、开源方案和架构设计。摘要需要简洁概括主要点。 字数限制:≤150字。需要包含关键信息:STM32N6运行YOLO,困难,方案(NPU、INT8量化、工具链),性能(34 FPS 9.4mJ)。结尾可能提到开源和生态。 写中文摘要。注意不超过150字。</think>本文探讨YOLO模型在STM32微控制器上的部署。集成NPU的STM32N6搭配轻量化YOL

2601_95807009的博客 257

【AI 赋能:Python 人工智能应用实战】16. BERT微调实战:中文新闻分类全流程(附模型蒸馏+ONNX部署完整代码)

中文新闻分类是NLP领域的经典实用任务,BERT模型凭借双向上下文建模能力,能有效解决中文歧义与长文本依赖问题,但存在推理速度慢、资源占用高的痛点。本文以THUCNews中文新闻数据集为核心,提供从数据预处理、BERT微调、模型蒸馏到生产部署的全流程实操指南。首先详解THUCNews的多编码读取与清洗(解决gbk/utf-8兼容问题);然后实现BERT微调,加入早停机制与混淆矩阵可视化,验证准确率达93.8%;接着用DistilBERT完成模型蒸馏,在仅损失0.6%准确率的前提下,将推理速度提升2.7倍。

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 1098

java数组总结_(二)Java数组特性总结,你真的了解数组吗?

一、数组的特殊性(一)数组标识符是一个引用,指向堆中创建的一个真实对象,这个对象(数组)保存了指向保存其他对象的引用。(二)数组中保存引用类型时保存的是对象引用,基本数据类型数组保存基本数据的值。(三)数组的length只表示数组能够容纳多少元素,不能保存实际保存的元素个数。(四)多维数组可以使用Arrays.deepToString()将多维数组转换成String。(五)不能使用泛型创建数组,例...

weixin_34438539的博客 158

流体仿真软件:COMSOL Multiphysics二次开发_(11).COMSOL与外部软件的数据交换

通过上述方法,您可以实现 COMSOL Multiphysics 与外部软件的数据交换,从而更好地集成和分析仿真结果。无论是从文本文件导入数据,导出数据到 MATLAB,还是通过 API 和 COMSOL Server 实现实时通信,都能满足不同场景下的需求。希望这些内容对您在流体仿真领域的开发工作有所帮助。

kkchenjj的博客 1553

转:js清空数组

方式1,splice 1 2 3 varary = [1,2,3,4];ary.splice(0,ary.length);console.log(ary);// 输出Array[0],空数组,即被清空了 方式2,length赋值为0 这种方式很有意思,其它语言如Java,其数组的length是只读的,不能被赋值。如 1 2 int[] ary = {1,2,3,4};...

morein2008的专栏 82

适航规章、标准,书籍资料下载汇总(增加DO-160G中英文版)

很多读者之前问我有没有DO-160G的资源,现在终于找到啦!如果大家有其他想要的资源,可以在留言区告诉我,有空我会帮大家找找看~文末有下载链接:更新日志:2024-9-28:初版。2024-10-21:增加DO-330英文版PDF下载。2024-10-30:增加DO-160G中文版(非机翻)和英文版PDF下载。以下是一些收集到的适航相关的资料,分享给大家。(如果没有你想要的资料,请留言,等找到会及时更新!

qq_41854911的博客 2761

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

【Matlab】Matlab数组元素复制的多种实现方法对比

本文深入对比了Matlab中数组元素复制的多种实现方法,包括repmat、kron和repelem等。针对不同的复制需求(整体块复制与元素级复制),分析了各方法的适用场景、性能表现与代码可读性,并提供了实战选择指南,帮助开发者根据Matlab版本和具体任务高效、精准地选用最佳工具。

s4t5u6v的博客 588

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

java数组复制的方式和效率比较

java中,数组的复制有以下三种方式: 1. 调用System.arraycopy(Arrays.copyOfRange可以当作第四种,但是底层调用的是System.arraycopy,所以,认为是同一种,下面是Arrays.copyOfRange的方法实现) public static T[] copyOfRange(U[] original, int from, int to, Cla

杨飞的专栏 1746

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

java clone性能比较_转 Java 4种数组复制方式的性能比较

个人理解:Arrays.copyOf()调用了基于本地方法和机器码的System.arrayCopy()方法,从原数组拷贝到一个临时新建数组并返回,返回数组长度取参数和原数组的较小值。也就是,传入长度太短时截取,太长了取原长。得出结论:如果多次扩容,要选定一个合适的大小,太小频繁扩容有创建数组开销,太大占用内存。packagecom.demo.main;importjava.util.Arrays...

weixin_42561192的博客 353

数组的复制,数组复制的三种方式

一、数组复制的三种方式 String[] a = {"1", "2", "3", "4", "5"}; // 方法一 // Arrays.copyOf() String[] b = Arrays.copyOf(a, a.length); System.out.println("Arrays.copyOf(): " + Arrays.toString(b)); // 方法二 // Objec

shenju2011的博客 4441

C#复制数组的两种方式,以及效率比较

  如何高效地进行数组复制?   如果把一个变量值复制给另外一个数组变量,那么2个变量指向托管堆上同一个引用。   如果想在托管堆上创建另外的一份数组实例,通常使用Array.Copy方法。   class Program { static void Main(string[] args) { int[] a = {1, 3, 6}; int[] b =new int[...

weixin_34162695的博客 1403

转 Java 4种数组复制方式的性能比较

个人理解:Arrays.copyOf()调用了基于本地方法和机器码的System.arrayCopy()方法,从原数组拷贝到一个临时新建数组并返回,返回数组长度取参数和原数组的较小值。也就是,传入长度太短时截取,太长了取原长。 得出结论:如果多次扩容,要选定一个合适的大小,太小频繁扩容有创建数组开销,太大占用内存。 packa...

a662852186的博客 162

Java 4种数组复制方式的性能比较

(1)从速度上看:System.arraycopy > clone > Arrays.copyOf > for (2)for的速度之所以最慢是因为下标表示法每次都从起点开始寻位到指定下标处(现代编译器应该对其有进行优化,改为指针),另外就是它每一次循环都要判断一次是否达到数组最大长度和进行一次额外的记录下标值的加法运算。 (3)查看Arrays.copyOf的源码可以发现,它其实本质上是调用了System.arr

司马懿的西山居 5853

C# 数组复制

本章讲述:C# 数组复制 1、Buffer.BlockCopy(把某个数组的一部分复制到另一个数组中)     注解分析:     Buffer.BlockCopy 则从本质上以字节为复制单位,这在底层语言C,C++的处理优势上,同理,效率之高可以理解。     public static void BlockCopy (Array src,int srcOffset,Array dst,int...

^@^lemon tea^@^ 8392

Java中各种数组复制方式的效率对比

选择合适的方法:在选择数组复制方法时,应根据具体需求和性能要求进行选择。对于大规模数组复制,推荐使用 System.arraycopy;对于简单的数组复制,而手动复制适合需要复杂逻辑的场景。性能考虑:在性能敏感的应用中,尽量避免使用手动复制,优先考虑使用 System.arraycopy。

xweiran的博客 553
上一篇: C# 调用C++ DLL (三)
下一篇: unity3d ulua framwork build打包后shader丢失的问题记录
Le_Sam
博客等级 码龄11年 342粉丝 53原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值