当前位置: 首页 > news >正文

百万点数组下memset、memcpy与for循环效率对比及原理分析

一.概述

    做上百万数组赋值及拷贝的时候,不得不考虑效率问题,一般计算机低于十万的数组赋值拷贝基本不用考虑效率问题(基本在1毫秒内完成),本文会对百万以上的数组下赋值及拷贝进行效率分析和对比。

二.代码实测

1.测试环境:QT5

2.测试代码

#include <QTime>

#include <QDebug>

#include <stdio.h>

#include <string.h>

#define ARRAY_SIZE    5000000  //五百万

//必须定义为全局数组,不能定义为局部变量,数组太大,定义为局部变量运行会崩溃

double array1[ARRAY_SIZE];

// 定义第二个包含100万个double元素的数组

double array2[ARRAY_SIZE];

// 用于赋值的源数组

double source_array[ARRAY_SIZE];

int main(int argc, char *argv[])

{

    // 定义第一个包含100万个double元素的数组

    for (int i = 0; i < ARRAY_SIZE; i++) {

        source_array[i] = (double)i;

    }

    qDebug() << "当前时间1:" << QTime::currentTime().toString("hh:mm:ss.zzz");

    // 使用for循环将array1清零

    for (int i = 0; i < ARRAY_SIZE; i++) {

        array1[i] = 0.0;

    }

    qDebug() << "当前时间11:" << QTime::currentTime().toString("hh:mm:ss.zzz");

    // 使用memset将array1再次清零

    qDebug() << "当前时间2:" << QTime::currentTime().toString("hh:mm:ss.zzz");

    memset(array1, 0, sizeof(double) * ARRAY_SIZE);

    qDebug() << "当前时间22:" << QTime::currentTime().toString("hh:mm:ss.zzz");

    // 使用for循环对array2进行赋值

    qDebug() << "当前时间3:" << QTime::currentTime().toString("hh:mm:ss.zzz");

    for (int i = 0; i < ARRAY_SIZE; i++) {

        array2[i] = source_array[i];

    }

    qDebug() << "当前时间33:" << QTime::currentTime().toString("hh:mm:ss.zzz");

    // 使用memcpy对array2进行内存拷贝赋值

    qDebug() << "当前时间4:" << QTime::currentTime().toString("hh:mm:ss.zzz");

    memcpy(array2, source_array, sizeof(double) * ARRAY_SIZE);

    qDebug() << "当前时间44:" << QTime::currentTime().toString("hh:mm:ss.zzz");

    return 0;

}

3.测试结果

  五百万点的情况下log打印:

当前时间1: "10:27:43.122"

当前时间11: "10:27:43.136"

当前时间2: "10:27:43.136"

当前时间22: "10:27:43.143"

当前时间3: "10:27:43.143"

当前时间33: "10:27:43.158"

当前时间4: "10:27:43.158"

当前时间44: "10:27:43.163"

可以看到memset和memcpy是for循环时间的40%~50%,也就是效率能提升一倍。

三.原理分析

1.函数实现的底层优化

memset 和 memcpy 的底层实现:memset 和 memcpy 是标准库函数,它们在不同的操作系统和编译器中都经过了高度的底层优化。这些函数通常是用汇编语言实现的,汇编语言可以直接操作计算机的底层硬件,绕过了高级语言的一些开销。

示例:在 x86 架构上,memcpy 可能会使用 SSE(Streaming SIMD Extensions)或 AVX(Advanced Vector Extensions)等指令集。这些指令集允许在一个时钟周期内同时处理多个数据元素,从而显著提高了数据复制的速度。

2.减少函数调用开销

for 循环的函数调用开销:当使用 for 循环来复制或设置内存时,每次循环都可能涉及到一些额外的操作,如循环条件的判断、循环变量的更新等。这些操作在每次循环时都会重复执行,增加了程序的开销。

memset 和 memcpy 的一次性调用:memset 和 memcpy 是一次性调用的函数,它们在函数内部完成所有的内存操作,避免了多次函数调用的开销。

3.数据访问模式的优化

for 循环的数据访问模式:在 for 循环中,每次循环通常只处理一个数据元素,这种逐元素的访问模式可能会导致频繁的内存访问,从而降低了效率。

memset 和 memcpy 的批量数据处理:memset 和 memcpy 会以更大的块为单位来处理数据,这样可以减少内存访问的次数,提高缓存命中率。例如,memcpy 可能会一次复制 4 字节、8 字节甚至 16 字节的数据,而不是每次只复制一个字节。

4.编译器优化

for 循环的编译器优化限制:虽然现代编译器会对 for 循环进行一些优化,但由于 for 循环的逻辑可能比较复杂,编译器的优化能力有限。

memset 和 memcpy 的编译器优化:编译器通常会对 memset 和 memcpy 进行特殊的优化,因为它们是标准库函数,编译器可以更好地预测它们的行为,并进行针对性的优化。

http://www.xdnf.cn/news/108325.html

相关文章:

  • 经典算法 小数点后的第n位
  • 语音合成之四基于LLM的语音合成
  • Sql刷题日志(day5)
  • JVM理解(通俗易懂)
  • 2025年渗透测试面试题总结-拷打题库14(题目+回答)
  • 时间自动填写——电子表格公式的遗憾(DeepSeek)
  • A13 自定义系统服务使用总结
  • Kafka集群
  • ABP-Book Store Application中文讲解 - Part 0:开发环境搭建
  • 意见反馈留言二维码制作
  • leetcode-枚举
  • Langchain coercion简介
  • deeplab语义分割训练自定数据集
  • leve1.4
  • LLama Factory从入门到放弃
  • iThenticate英文查重系统怎么用?
  • 【AI论文】在非政策指导下学习推理
  • 中药企业数字化转型:从传统制造到智能制药的跨越
  • 3D模型格式转换工具HOOPS Exchange 2025.3.0更新:iOS实现Rhino格式支持!
  • TypeScript-知识点梳理
  • 艾瑞:高标准化场景AI渗透越来越高,Agent将是未来AI+HRM的最佳形态
  • 【UML建模】数据流图 绘制
  • 【论文#目标检测】Attention Is All You Need
  • sql 根据时间范围获取每日,每月,年月的模版数据
  • 高等数学第一章---函数与极限(1.3 函数的极限)
  • CF2103F Maximize Nor
  • 车载信息安全架构 --- 汽车网络安全
  • 在面试中被问到spring是什么?
  • 分糖果——牛客
  • 0基础可以考MySQL OCP么?备考时间需要多久?