数组或结构体赋值时memcpy与直接赋值的效率比较

news2024/10/6 20:27:29

先上结论:

  • 二者不一定谁快
  • 通常情况下,数组维度越大,使用memcpy效率更高
  • 数组维度越大,直接赋值耗时主体是循环耗时

Note:

  1. “等号赋值”被编译器翻译成一连串的MOV指令,而memcpy则是一个循环。“等号赋值”比memcpy快,并不是快在拷贝方式上,而是快在程序流程上
  2. 连续的MOV指令要比循环MOV快
  3. 在循环方式下,每一次MOV过后,需要: ①判断是否拷贝完成;②跳转以便继续拷贝
  4. 循环除了增加了判断和跳转指令以外,对于CPU处理流水产生的影响也是不可不计的

转自传送门

如果是低维数组,直接展开循环进行赋值效率更高,这样可以避免判断与跳转对CPU时间的占用,也就是空间换时间,但要注意的是,并不是越展开越好(即使不考虑对空间的浪费),展开也应该有个度。

因为CPU的快速执行很依赖于cache,如果cache不命中,CPU将浪费不少的时钟周期在等待内存上(内存的速度一般比CPU低一个数量级)。而小段循环结构就比较有利于cache命中,因为重复执行的一段代码很容易被硬件放在cache中,这就是代码局部性带来的好处。而过度的循环展开就打破了代码的局部性。

GCC有自动将循环展开的编译选项,如-funroll-loops

测试代码见文末,下面分情况进行几个小实验。


1. 数组1维,对比memcpy与赋值

  • 无优化选项
    在这里插入图片描述
  • -O3编译
    在这里插入图片描述

2. 数组1000维,对比memcpy与赋值

  • 无优化选项
    在这里插入图片描述

  • -O3编译
    在这里插入图片描述

  • 屏蔽循环中的赋值,无优化选项
    在这里插入图片描述

  • 屏蔽循环中的赋值,-O3编译
    在这里插入图片描述


测试代码如下:

#include <stdio.h>
#include <sys/time.h>
#include <unistd.h>
#include <string.h>

#define DIMENSION_MIN 10
#define DIMENSION_MAX 200

int main()
{
	int count = 1000000;
	double data[DIMENSION_MIN] = {0};
	double bate[DIMENSION_MIN] = {0};
	
	struct timeval tv;
	double dT1=0,dT2=0;
	double start,stop;

	gettimeofday(&tv,NULL);
	start = (double)(tv.tv_sec*1000 + tv.tv_usec*0.001); //ms		
	for(int i=0;i<count;i++)
	{
		memcpy(bate,data,sizeof(bate));
	}
	gettimeofday(&tv,NULL);
	stop = (double)(tv.tv_sec*1000 + tv.tv_usec*0.001); //ms	
	dT1 = stop - start;

	gettimeofday(&tv,NULL);
	start = (double)(tv.tv_sec*1000 + tv.tv_usec*0.001); //ms		
	for(int i=0;i<count;i++)
	{
		for(int j=0;j<DIMENSION_MIN;j++)
		{
			bate[j]=data[j];
		}
	}
	gettimeofday(&tv,NULL);
	stop = (double)(tv.tv_sec*1000 + tv.tv_usec*0.001); //ms	
	dT2 = stop - start;
	
	printf("\n\n\n%d维数组的比较:\n",DIMENSION_MIN);
	printf("       for take time: %lfms\n",dT2);
	printf("    memcpy take time: %lfms\n\n\n",dT1);
	
	/***********************************************************************/

	double data1[DIMENSION_MAX] = {0};
	double bate1[DIMENSION_MAX] = {0};

	gettimeofday(&tv,NULL);
	start = (double)(tv.tv_sec*1000 + tv.tv_usec*0.001); //ms		
	for(int i=0;i<count;i++)
	{
		memcpy(bate1,data1,sizeof(bate));
	}
	gettimeofday(&tv,NULL);
	stop = (double)(tv.tv_sec*1000 + tv.tv_usec*0.001); //ms	
	dT1 = stop - start;

	gettimeofday(&tv,NULL);
	start = (double)(tv.tv_sec*1000 + tv.tv_usec*0.001); //ms		
	for(int i=0;i<count;i++)
	{
		for(int j=0;j<DIMENSION_MAX;j++)
		{
			bate1[j]=data1[j];
		}
	}
	gettimeofday(&tv,NULL);
	stop = (double)(tv.tv_sec*1000 + tv.tv_usec*0.001); //ms	
	dT2 = stop - start;
	
	printf("%d维数组的比较:\n",DIMENSION_MAX);
	printf("       for take time: %lfms\n",dT2);
	printf("    memcpy take time: %lfms\n\n\n",dT1);

	return 0;
}

参考文献:

  • https://blog.csdn.net/pngynghay/article/details/17142401
  • https://developer.aliyun.com/article/8924
  • https://www.zhihu.com/question/356017800/answer/2786064715

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

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

相关文章

05mysql---函数

目录 1:日期函数 2:字符函数 3:数值函数 4:流程函数 1:日期函数 select 函数(参数) 函数功能举例curdate()返回当前日期2023-05-17curtime()返回当前时间14:44:33now()返回当前日期和时间2023-05-17 14:44:33year(date)获取指定date的年份month(date)获取指定date的月份day…

【简介】限流

限流 为什么要限流限流算法单机限流计数器算法滑动窗口算法漏桶算法令牌桶算法 分布式限流配额算法 限流策略限流位置 为什么要限流 作为有追求的程序员&#xff0c;我们都希望自己的系统跑的飞快&#xff0c;但是速度再快&#xff0c;系统处理请求耗时也不可能为0&#xff0c…

线程池下载4K壁纸

学习记录 学习记录 一、目标 aHR0cHM6Ly9waWMubmV0Ymlhbi5jb20vDQo 拿到每张图片的href 和 标题&#xff0c;跳转到详情页进行图片下载地址的提取并请求实现图片本地下载 二、代码实现 """ CSDN: 抄代码抄错的小牛马 mailbox&#xff1a;yxhlhm2002163.com…

计算机毕业论文内容参考|基于java的房产营销系统的设计与实现

文章目录 导文摘要前言绪论课题背景课题内容相关技术与方法介绍技术分析技术设计技术实现总结与展望本文总结后续工作展望导文 计算机毕业论文内容参考|基于java的房产营销系统的设计与实现 摘要 当今社会,随着经济的快速发展和人们对生活品质的不断提高,房地产行业正在面临…

Java --- docker安装redis

目录 一、拉取redis容器镜像 二、新建目录 三、拷贝redis.conf文件模板进/app/redis目录 四、修改redis.conf文件 五、启动redis镜像服务 一、拉取redis容器镜像 docker pull redis:7.0.0 二、新建目录 mkdir -p /app/redis 三、拷贝redis.conf文件模板进/app/redis目录 cp …

Java面试(4)面向对象

文章目录 概念1. 面向对象和面向过程的区别2. 面向对象三大特征 类1. 接口和抽象类有什么共同点和区别&#xff1f;2. 深拷贝和浅拷贝区别了解吗&#xff1f;什么是引用拷贝&#xff1f;3. 内部类1. 内部类2. 内部类的优点3. 内部类有哪些应用场景4. 局部内部类和匿名内部类访问…

python 3.8 + tensorflow 2.4.0 + cuda11.0 的问题

版本匹配 &#x1f517;从源代码构建 | TensorFlow 报错&#xff1a;Could not load dynamic library ‘cupti64_110.dll’; dlerror: cupti64_110.dll not found 是因为我电脑中的 cuda 版本以前是 10&#xff0c;现在是 11.4 &#xff0c;所以需要安装对应版本的 cudatoolk…

基于粒子群算法的微网经济优化调度——附Matalb代码

目录 摘要&#xff1a; 代码主要内容&#xff1a; 研究背景&#xff1a; 微电网模型&#xff1a; 粒子群算法&#xff1a; 运行结果&#xff1a; Matlab代码分享&#xff1a; 摘要&#xff1a; 提出了一种经济与环保相协调的微电网优化调度模型&#xff0c;针对光伏电池…

SAP入门到放弃系列之需求管理的基本要素

需求管理目标&#xff1a; 一般而言&#xff0c;生产计划&#xff08;PP&#xff09;的总体目标&#xff0c;特别是需求管理的总体目标是通过减少以下内容来更好地为客户服务&#xff1a; 补货提前期存货成本 需求管理的要素&#xff1a; 需求管理工作的主要要素广义上可分…

2013蓝桥杯真题省赛翻硬币 C语言/C++

[蓝桥杯 2013 省 B] 翻硬币 题目背景 小明正在玩一个“翻硬币”的游戏。 题目描述 桌上放着排成一排的若干硬币。我们用 * 表示正面&#xff0c;用 o 表示反面&#xff08;是小写字母&#xff0c;不是零&#xff09;&#xff0c;比如可能情形是 **oo***oooo&#xff0c;如果…

暴涨700w播放,星穹铁道恰饭频频登上B站爆款热榜!

B站作为现在年轻一代聚集的多元化社区&#xff0c;游戏内容则是社区内受众较为广泛的存在&#xff0c;而星铁作为面向年轻群体的回合制游戏&#xff0c;自然是赢得B站核心用户群体的青睐。 4月26日&#xff0c;暌违已久的手游《崩坏&#xff1a;星穹铁道》&#xff08;后文简称…

【Java】平时开发中遇到的问题你是否遇到过?

文章目录 前言一、六类典型空指针问题1.1包装类型的空指针问题1.2 级联调用的空指针问题1.3 Equals方法左边的空指针问题1.4 ConcurrentHashMap 这样的容器不支持 Key&#xff0c;Value 为 null。1.5 集合&#xff0c;数组直接获取元素1.6 对象直接获取属性 二、日期YYYY格式设…

Linux和UNIX的关系及区别(详解)

UNIX 与 Linux 之间的关系是一个很有意思的话题。在目前主流的服务器端操作系统中&#xff0c;UNIX 诞生于 20 世纪 60 年代末&#xff0c;Windows 诞生于 20 世纪 80 年代中期&#xff0c;Linux 诞生于 20 世纪 90 年代初&#xff0c;可以说 UNIX 是操作系统中的"老大哥&…

Fortinet FortiNAC RCE漏洞复现(CVE-2022-39952)

0x01 产品简介 FortiNAC(Network Access Control) 是Fortinet的一种零信任网络访问控制解决方案&#xff0c;可增强用户对企业网络上的物联网 (IoT) 设备的监控。NAC 是零信任网络访问安全模型的重要组成部分&#xff0c;在该模型中&#xff0c;IT 团队可以轻松了解正在访问网络…

低代码让开发变得不再复杂

文章目录 前言低代码 VS 传统开发为什么选择IVX&#xff1f;平台比对总结 前言 在数字化的时代背景下&#xff0c;企业都面临巨大的数字化转型的挑战。为了应对这样的挑战&#xff0c;企业软件开发工具和平台也在不断革新和发展。低代码开发平台随之应运而生&#xff0c;成为了…

面向对象编程与面向过程编程的区别

面向过程&#xff1a; 以坦克飞机大战为例&#xff0c;如果按面向过程的思路去书写代码&#xff0c;则需要按如下顺序进行编码&#xff1a; 游戏初始化确定一台坦克的位置绘制坦克确定多架飞机的位置绘制飞机为坦克设置上下左右四个转向为坦克添加按下键盘k键发射子弹为所有飞…

ATFX国际:国内成品油价格下调,国际油价仍维持震荡态势

ATFX国际&#xff1a;5月16日&#xff0c;发改委发布成品油价格下调通知&#xff0c;其中提到&#xff1a;国内汽、柴油价格每吨分别降低380元和365元。以上海地区为例&#xff0c;价格下调后&#xff0c;每吨汽油的售价为9255元&#xff0c;每吨柴油的价格为8225元。经计算&am…

【容器适配器的认识与模拟】

目录&#xff1a; 前言一、引入二、容器适配器&#xff08;一&#xff09;stackdequestack模拟实现 &#xff08;二&#xff09;queuequeue模拟实现为什么栈和队列要使用deque &#xff08;三&#xff09;priority_queuepriority_queue模拟实现 总结 前言 打怪升级&#xff1a…

小程序获取用户信息实现一键登录

文章目录 旧版获取用户信息实现登录流程login页面代码个人中心页面代码全局app.vue代码下面是小程序获取用户信息最新调整的方式 温馨提示 &#xff1a;以下小程序登录方式只适用于2.27.1版本库以下使用 详情请看微信官方文档调整 旧版获取用户信息实现登录流程 由于我是在hbu…

公司招了一个腾讯拿30K的人,让我见识到了什么是天花板···

前言 人人都有大厂梦&#xff0c;对于软件测试人员来说&#xff0c;BAT 为首的一线互联网公司肯定是自己的心仪对象&#xff0c;毕竟能到这些大厂工作&#xff0c;不仅薪资高待遇好&#xff0c;而且能力技术都能够得到提升&#xff0c;最关键的是还能够给自己镀上一层金&#…