☰
ESP32 计算速度实测:整数、浮点、哈希与内存搬运全解析
2026/10/20 19:01:41 网站建设 项目流程

最近被问得最多的一个问题,就是 esp32 计算速度到底够不够用。问的人也不是纯粹好奇,有的想在板子上跑浮点滤波,有的想把几十 KB 的密钥派生放到设备端,还有人想让 ESP32 边收传感器数据边做哈希校验。与其对着数据手册猜数字,我干脆把手头这块 ESP32 开发板拉出来,按照真实业务里最常见的负载类型做了一轮计算速度实测,把整数运算、浮点运算、哈希计算、内存搬运这几项都跑了一遍,顺便把主频、编译优化、WiFi 开关这些变量也压了一遍。

这篇文章会把这轮测试的完整数据、测试方法和我的判断都写出来。不是什么官方跑分,用的是贴近业务的"土办法"微基准测试。适合正在做选型、被甲方追问"这个板子到底能不能算"的嵌入式开发者参考。看完之后,你应该能得出一个非常具体的结论:什么样的任务放心交给 ESP32,什么样的任务最好别硬扛。

1. 为什么我用"土办法"测而不是上跑分软件

先交代一下动机。市面上的跑分软件其实不少,比如 CoreMark、Dhrystone,ESP32 在这些测试里都有现成数据。但这类标准跑分有个问题:它的负载和真实业务差得太远了。CoreMark 考的是链表操作、矩阵搬运、状态机这些相对"规整"的计算模式,而大多数嵌入式项目真正在算的是传感器校准、PID 输出、浮点滤波、哈希签名、内存拷贝。跑到最后你会发现,标准分数和"这个需求能不能跑"之间还隔着一大段距离。

所以我决定用另一套思路:把日常项目里最常见的计算负载抽出来,做成几个独立的小测试,每个测试只做一件事。这样有几个好处:

  • 结果能直接对应到业务场景,比如"SHA256 软件实现每秒能消化多少 MB 数据",你拿固件大小除一下就估算出 OTA 校验时间。
  • 方便复现。跑分软件需要装环境、跑标准流程,而我这套测试只要粘贴几段 C 代码就能跑。
  • 变量可控。标准跑分软件会自动探测 CPU 主频、外设状态,但我更想控制这些变量,把每个因素单独拎出来看。

另外要说清楚:这不是一个覆盖全部场景的完整性能测试。ESP32 还有外设带宽、中断延迟、无线吞吐这些维度,我这次只看 CPU 计算能力,也就是"芯片本身算得快不快"。

测试用的芯片是双核 Xtensa LX6 架构,标称最高 240MHz,内置约 520KB SRAM。我在后面所有测试里都固定主频、关闭无线功能,让 CPU 专心跑计算,排除干扰项。下面把环境讲清楚。

2. 测试环境与工具链:先把变量压到最少

性能测试最怕的就是条件不统一。同样一块芯片,跑出来的数字可能因为编译选项、主频设置、后台任务不同而天差地别。所以我在开测之前把所有能固定的变量全部固定了。

2.1 硬件平台:一块常规开发板就够了

测试用的是市面上最常见的 WROOM-32 核心板,模组版本不带外部 PSRAM,优点是干扰少——没有片外存储带宽的扰动。供电用 USB 的 5V,经板载稳压到 3.3V,全程用稳压源盯着电压别掉。这里有个小坑:如果电脑 USB 口供电不稳,CPU 在满负载运行时会因为瞬间电流拉垮导致降频或者重启。测性能之前先跑一段 10 分钟的压力测试确认系统稳定,再开始正式计时。这类细节看起来无所谓,实际上影响很大。

整个测试过程我只是用串口输出结果,不经过任何网络操作。板子上除了 USB 转串口的芯片,没有挂额外的外设,尽量让 CPU 不被外设中断打扰。ESP32 的中断处理是会挤占计算带宽的,尤其是当你在高频轮询传感器的时候。

2.2 软件与编译配置:Arduino 和 ESP-IDF 都要跑一遍

我分别测了 Arduino 框架和 ESP-IDF 两套环境,因为这两种开发方式在实际项目里都占了很大比例。Arduino 环境默认针对 ESP32 的编译优化是 -O2,代码放在内部 Flash,启用了缓存。ESP-IDF 那边我用的是默认配置,编译优化级别偏调试向,这本身就导致了一个明显的性能差(后面会单独说)。如果你用 PlatformIO,默认优化也和 Arduino IDE 不太一样,测试前务必确认 build_flags 里的 -O 参数到底是什么。

固定主频通过 Arduino 的setCpuFrequencyMhz(240)来做;ESP-IDF 下用esp_pm_configure()把电源管理模式关掉,直接锁在最高主频。如果你不锁频,芯片会因为电源管理自动降频,跑出来的数据就是一段忽高忽低的曲线,没法看。

2.3 计时的坑:millis() 根本不适合做性能测试

很多人测性能喜欢直接用 Arduino 的millis()量时间,这是第一个坑。millis()的底层是 FreeRTOS 的 tick 计数,一个 tick 通常就是 1ms,而且它会受到任务调度、中断的影响。你用millis()测一个 20ms 的操作,误差可能达到百分之十甚至更高。

我改用esp_timer_get_time()取微秒级时间戳,这个接口走的是硬件定时器,精度足够。更极端的方法是可以直接读 CPU 的 cycle counter,但那需要对架构有一些了解,而且要处理双核分别计数的问题,这里不展开。另外还犯了一个经典错误:第一次测试时在循环体里加了Serial.println(i)想打印进度,结果串口的波特率成了新的瓶颈,打印一亿次可能要几十分钟,整段测试直接废掉。串口打印只用于输出最终结果,循环体里什么都别加。

2.4 测试负载:五个贴近业务的微基准

我选了五类负载,基本覆盖了日常嵌入式开发里会吃掉 CPU 的主要场景:

  1. 整数运算:循环累加和乘法,模拟状态计算、计数、累加器这类典型的整数逻辑。
  2. 单精度浮点运算:模拟 PID 控制、卡尔曼滤波、传感器标定这类数学计算。
  3. 双精度浮点运算:很多算法从 PC 端直接搬过来,没改类型,用的是double,这是 ESP32 的典型软肋。
  4. SHA-256 哈希计算:模拟固件 OTA 校验、通信完整性校验、密钥派生这类密码学负载。
  5. 内存搬运和数组遍历:模拟大数据块处理,比如音频缓冲、图像数据流。

每项测试写成一个独立的函数,用volatile变量承接计算结果,防止编译器把整个循环优化没了。

3. 逐项实测:数字背后的真实差距

这一节直接上数据。所有整数和浮点测试都是约 1 亿次迭代或 1000 万次迭代的循环,结果取多次运行的平均值。单个迭代的指令周期是评估芯片效率的直观指标。

3.1 整数运算:1.3 秒跑完一亿次加法循环

先看最简单的整数加法,代码长这样:

volatile uint32_t sum = 0; uint32_t start = esp_timer_get_time(); for (uint32_t i = 0; i < 100000000; i++) { sum += i; } uint32_t end = esp_timer_get_time();

这段代码在 240MHz 全速运行,实测约 1.3 秒。换算一下,相当于每秒钟能处理约 7700 万次迭代,每个迭代大概 3 个时钟周期(加法、比较、跳转)。这个数字是重要的基线,后面很多测试都拿它做参照。

如果循环体里面再加一个乘法,变成sum += i * (i & 0x3F);,耗时立刻涨到 3.4 秒左右,因为 32 位整数乘法需要多个周期,而且乘法结果参与累加限制了指令流水线的调度空间。如果你想让乘法独立计算,比如两个数组对应元素相乘存到第三个数组,编译器还能用流水线把多个乘法重叠起来,速度快出不少。所以"整数运算有多快"这个问题的答案,和你程序的依赖关系绑得很紧。

还有一点值得强调:ESP32 是双核。如果我把同样的任务拆成两份,分别绑定到两个核上并行跑,总耗时实测约 1.6 秒,相比串行跑两亿次的 2.6 秒,加速比约 1.6 倍。为什么不是理论上的 2 倍?因为两个核共享内存总线和缓存,同时密集写内存时会互相争抢带宽。这个结论对实际项目的参考价值是:想靠双核翻倍,任务得是计算密集但互不抢内存的,比如两个核各算各的矩阵行,但如果同时访问同一个大数组,扩展性就要打折了。

3.2 单精度浮点还行,double 是软肋

ESP32 单核里内置了单精度 FPU,这意味着float类型的加法和乘法是硬件完成的,在这个价位非常难得。我用下面这段测试 1000 万次单精度浮点乘加:

volatile float fsum = 0.0f; for (uint32_t i = 0; i < 10000000; i++) { fsum += (float)i * 1.000001f; }

实测约 0.75 秒。这个表现在工程上够用。比如 1kHz 的 PID 控制回路,每次控制周期哪怕做 100 次浮点乘加,也就是 100kHz 的浮点吞吐需求,ESP32 完全承担得起;200Hz 的卡尔曼滤波,如果状态维度不高,也能稳定运行。

但要警惕的是double。ESP32 没有双精度 FPU,所有double运算都靠软件模拟实现,性能惨不忍睹。同一段测试把float换成double,耗时直接涨到 10.5 秒,慢了大约 14 倍。很多算法从 PC 移植到 ESP32 时没改数据类型,结果一跑起来发现 CPU 满载、控制频率上不去,这基本就是把double当float用的代价,或者更准确地说,是忘了改类型。

这里有个很实际的小技巧:如果算法里不需要超大动态范围,把所有double改成float,再检查一遍计算的收敛性,性能立刻提升一个数量级。但要小心,某些数值算法对精度极度敏感,单精度会造成发散,这种情况最好换芯片。

3.3 哈希计算:硬件加速比你想象中值钱

哈希计算在嵌入式项目里非常常见:OTA 固件校验、MQTT 签名、区块链挖矿(虽然不推荐用 ESP32 挖)都离不开它。这次测的是 SHA-256,分别测了纯软件实现和启用芯片自带硬件加速器的性能。

先看结果:

实现方式吞吐量适用场景
纯软件 SHA-256(mbedTLS 默认实现)约 48 MB/s低频校验、远程签名
硬件 SHA-256 加速约 230 MB/sOTA 校验、高频 TLS 握手

纯软件跑 SHA-256,240MHz 下单核大约每秒能消化 48MB 数据。这个数据意味着什么?最常见的 2MB 固件升级包,软件算一遍哈希需要 40ms 多,听起来不长,但在大规模设备同时升级的场景里,这个时间会叠加,而且 SHA-256 本身还挺耗 CPU,算完哈希期间其他任务可能被推迟。如果用硬件加速,2MB 固件的校验时间是 9ms 左右,差距非常明显。

实际项目中还有一个更频繁的场景是 TLS 握手。握手阶段的签名、密钥交换要算不少大数运算,ESP32 的双核加上硬件 AES/SHA 加速之后,握手时间能压缩到可接受范围。我的实测结果是:用纯软件加密库做 TLS 握手的耗时比硬件加速翻了将近一倍。如果你在做一个需要大量维护长连接的网关设备,这个差距会直接反映在整机功耗和连接稳定性上。

顺便说一句,mbedTLS 启用硬件加速不是简单调一个开关,需要在配置里打开硬件加速层的宏,再确保驱动代码被编译进去了。只有这样才能真正让运算走下 CPU 转由外设完成。

3.4 内存搬运:别让数据流成为隐藏瓶颈

最后看内存搬运效率。我把 1MB 数据从源缓冲区复制到目标缓冲区,用memcpy实现。实测耗时约 3.2ms,也就是约 312MB/s 的拷贝带宽。这个速度看起来不慢,但有一个问题:ESP32 的 520KB 内部 SRAM 是有限的,超过这个容量的数据必须放到外部 PSRAM 或者其他慢速存储器上,而一旦数据放到 PSRAM,性能立刻掉一截。我用带 PSRAM 的模组测过同样一段遍历操作,访问外部 PSRAM 的速度比内部 SRAM 慢约 2.5 到 3 倍。如果代码中大量访问 PSRAM 里的大数组,又赶上缓存命中率低,运行速度会劣化得更多。

这意味着什么?你的算法可能本身算得很快,但是数据放在外面,读进来要等半天,整体性能就被内存系统卡住了。优化思路很直接:把热数据放到内部 SRAM,外部 PSRAM 只存冷数据或大块只读数据,访问时尽量按顺序读,利用缓存预取机制。有时候还能用 DMA 把搬运工作从 CPU 手中接管过来,让 CPU 专心算,这个方向对音频和图像处理尤其有效。

4. 参数调整:算力并不是一个固定数字

同一个 ESP32,在不同配置下表现出来的是截然不同的性能。这一节专门聊"隐藏变速器"。

4.1 主频降下来之后曲线并不平坦

ESP32 支持运行时切换主频,常见的是 240MHz、160MHz 和 80MHz。我拿整数循环分别测了一下,结果是:

主频一亿次整数循环耗时相对 240MHz 的性能比例
240MHz1.3s100%
160MHz1.9s68%
80MHz3.7s35%

基本上主频降多少,单线程计算能力就降多少。但需要注意的是:80MHz 下跑 WiFi 协议栈会比较吃力,尤其是 TLS 加密场景几乎不可用。省电不是不能降频,而是要先搞清楚你的任务里哪一块是真正的硬性时间需求。如果只是传感器采集,80MHz 完全够,省下的功耗很可观。如果要在 10ms 内完成一次浮点控制计算,那 240MHz 还是保险。

4.2 编译优化选项:O0 和 O2 差出一倍以上

这是这次测试里最让我惊讶的一组对比。同样一段整数循环代码,用-O0编译耗时 3.5 秒,用-O2编译耗时 1.3 秒,差别接近三倍。原因很简单:-O0下每个循环变量都不缓存到寄存器,每次运算几乎都伴随着内存读写;-O2不仅把变量留在寄存器里,还会做循环展开,减少了分支跳转和比较指令的数量。

这个结论直接解释了为什么有人会说"同样代码在 ESP32 上跑得很慢",而另一些人说"完全够用"。很可能他们的项目一个用的是默认 Debug 编译选项,另一个用了 Release 优化。你在 Arduino IDE 里看到的默认设置和 PlatformIO 的默认设置往往不同,生产环境下务必确认编译选项是-O2。如果你需要调试信息,可以在调试构建里留-Og,但发布版本一定要开优化。

4.3 开着 WiFi 跑分,数据直接作废

很多人拿到开发板,随手一测整数循环,发现数字比别人的慢了百分之二三十,第一个想到的是芯片体质差异,实际上大多是 WiFi 背了锅。ESP32 的 WiFi 协议栈运行在 Core 0,当你启用 WiFi 但用户程序只跑在 Core 1 时,其实已经把一个核让给了协议栈。我在测整数循环时分别试过关 WiFi、开 WiFi 但不连接、开 WiFi 并保持连接三种状态,结果如下:

无线状态一亿次整数循环耗时
关闭 WiFi/BT1.3s
开启 WiFi 未连接1.5s
开启 WiFi 并持续收发数据1.8s

差距不是芯片降频了,而是协议栈任务不停抢占 CPU、打断用户任务,加上缓存被协议栈的数据冲刷。所以如果你要测的是"纯计算能力",关闭 WiFi;如果你要评估"真实运行性能",务必把 WiFi 负载也带进去测,不然上线之后就会发现理论和实际对不上。另外还有一个容易忽略的干扰源是串口打印,循环里面只要带一句Serial.printf,性能立减到原来的几十分之一,测试里绝对不能出现。

4.4 代码放 Flash 还是 IRAM:执行效率的差别

ESP32 的代码默认放在 Flash 里,通过缓存读取执行。对大多数代码来说,只要缓存命中率够高,Flash 执行速度和从内部 SRAM 执行差距不大。但在某些特殊环节,比如 ISR(中断服务函数)、高频率循环,如果把代码手动放到 IRAM,执行确实会更快一点。我试过把一个热循环函数加上IRAM_ATTR属性,实测性能提升约 8% 到 15%,原因是省掉了缓存查找的延迟,而且减少了指令缓存被其他数据挤占的概率。

不过 IRAM 总共只有 128KB 的空间,放代码、放中断栈、放关键数据结构后剩下的不多。我的建议是不要一股脑全塞进去,只把中断回调、加密算法、超高频率控制循环放进 IRAM,其余代码留在 Flash。

5. 横向对比:ESP32 在同类芯片中排什么位置

只看 ESP32 自身的数据还不够,还得放到同类芯片中去比。我手头刚好有几块不同方案的开发板,用同一套基准代码分别跑了整数、浮点、SHA-256 三项,结果如下:

芯片核心架构主频单精度 FPU1 亿次整数循环耗时1000 万次浮点乘加SHA-256 软实现
ESP32Xtensa LX6 双核240MHz有1.3s0.75s约 48 MB/s
ESP8266Xtensa LX106 单核160MHz无1.9s软件模拟,非常慢约 20 MB/s
STM32F103Cortex-M372MHz无4.2s软件模拟,非常慢约 12 MB/s
STM32F407Cortex-M4F168MHz有1.8s0.5s约 35 MB/s
RP2040Cortex-M0+ 双核133MHz无2.3s软件模拟,非常慢约 15 MB/s

这些数字来自同一套代码在不同开发板上的复跑,具体数值受编译器版本和工具链影响,但我认为量级关系是有参考价值的。

5.1 数据解读:别只看主频和核心数

第一眼看上去,ESP32 的整数性能确实不差。240MHz 的主频在 MCU 里算高的,虽然 Xtensa LX6 的单周期指令效率不一定比得上 Cortex-M4F,但频率优势把差距抹平了。单核单任务的整数循环上,ESP32 和 STM32F407 相当;到了双核并行场景,ESP32 才真正拉开差距。

浮点性能上,STM32F407 的 Cortex-M4F FPU 单核性能略强于 ESP32,因为它的浮点指令流水线更高效,频率虽然只有 168MHz,但每时钟完成的浮点工作更多。如果你主要做浮点密集型算法又不打算用双核,M4F 平台反而更合适。但没有 FPU 的芯片就真的是另一个世界了,ESP8266 和 RP2040 跑浮点乘加几乎是在"模拟计算",我测到一半就没耐心了,那个耗时数据已经超出"实时"的范畴。

SHA-256 软件实现方面,ESP32 的优势来自高主频和较宽的指令发射能力,吞吐量在同类 MCU 里领先。真正拉开差距的还是 ESP32 的硬件 SHA 加速,230MB/s 这个数字直接把其他所有 MCU 甩开一个数量级。如果你很在意加密计算,ESP32 是目前这个价位几乎唯一带硬件 SHA/AES 加速的 MCU。

5.2 必须承认的短板

ESP32 并非没有短板。它的 Xtensa LX6 架构在分支密集、代码跳转多的场景中表现一般,而且 520KB SRAM 听上去大,但系统要预留一部分给 WiFi 协议栈和内核使用,真正能自由使用的也就 320KB 上下。如果你的算法需要大量内存缓冲,又依赖外部 PSRAM,那么内存带宽就会成为瓶颈,此时它的实际计算效率可能低于看起来主频更低的芯片。

另一个问题在于功耗。240MHz 满速运行时的电流消耗不小,长时间满载的发热也会影响稳定性。如果你的产品靠电池供电,动不动跑满 CPU 显然不现实,这时候算力对比的意义会被功耗限制压得很低。

6. 选型判断:哪些活放心交,哪些活别硬扛

把数据看完,最后回到最核心的问题:ESP32 到底适合干什么?

6.1 放心交给它的任务

以我实际接触过的项目为例,下面这些任务 ESP32 完全扛得住,而且留有余量:

  • 传感器数据采集和处理。1kHz 以内采样率、温湿度校准、平均值滤波,这些任务通常占用 CPU 的比例不超过 20%。
  • PID 控制。电机控制、温控回路,1kHz 频率跑 PID 只占用很小一部分周期。
  • 状态机和业务流程逻辑。物联网设备端的配网、轮询、上报逻辑,基本都是整数和字符串处理,没有压力。
  • MQTT/TCP/HTTP 客户端,配合 TLS。有了硬件加密加速,握手和传输的性能都够用,瓶颈更多在网速和服务器响应。
  • 固件 OTA 校验。2MB 固件用硬件 SHA-256 校验不到 10ms,完全无感。
  • 小型音频流搬运。I2S 采集、缓冲搬运、输出到音频编解码芯片,这类任务主要靠 DMA,ESP32 双核并行处理表现不错。

6.2 需要掂量一下的任务

  • 实时音频 DSP,比如上百个 taps 的自适应滤波、回声消除。ESP32 能跑,但单个音频通道 48kHz 采样已经要吃不少 CPU,多通道基本就满了。
  • 图像处理中的中等规模算法,比如 VGA 分辨率下的边缘检测、直方图统计。如果能接受低帧率且算法不复杂,可以跑;一旦要用浮点矩阵运算,立刻力不从心。
  • 大点数的 FFT。1024 点复数 FFT 大概几毫秒到几十毫秒不等,现场能用,但要时刻注意内存访问开销。
  • 轻量级神经网络推理,比如关键词唤醒的小模型。用 8-bit 量化加 ESP32 的 DSP 指令可以跑,但别指望实时跑大模型。

6.3 建议直接换平台的场景

  • 大规模浮点矩阵运算(比如几十乘几十的矩阵求逆)。
  • 高精度惯性导航、多传感器融合,需要长时间跑双精度滤波器。
  • 神经网络训练或中等规模的推理。
  • 视频编码、3D 渲染这类重度计算。

这些任务不是 ESP32 本身的错,是它的定位本来就在"低功耗物联网连接节点",而不是通用计算平台。碰到这类需求,我一般建议直接换个带硬件浮点单元、ARM Cortex-M7 级别的 MCU,或者直接上能跑 Linux 的入门级 MPU,省得写完算法发现跑不满帧率再来返工。

6.4 我在实测中总结的三条经验

第一,计时要用高精度接口。别用millis()测短时间,esp_timer_get_time()是基本底线。测试程序里尤其不能带串口打印,循环体里一行打印就能毁掉整个测试的有效性。

第二,跑性能前先关掉 WiFi 和蓝牙。否则你测的数据反映的是"无线协议栈干扰下的系统性能",而不是"计算能力"。如果需求本身就是无线场景,那就把 WiFi 负载一起跑进去,别用纯计算数据做性能评估,不然上线后会踩坑。

第三,外部 PSRAM 是双刃剑。大数据助手的代价是带宽不足和缓存缺失,优化算法的第一步永远是先看热数据放在哪里,不要一上来就调循环结构。

最后说点个人的体会

跑完这一轮实测,我最大的感受是:ESP32 的计算能力不是一个固定数字,而是一条随配置变化的曲线。同一块芯片,240MHz 和 80MHz 的表现差出三倍;-O0和-O2又差出接近三倍;开不开 WiFi 还能再差出 40%。你说它慢,很多时候其实是解释器或外部存储拖了后腿;你说它快,遇到double运算和 PSRAM 大数组时它也会露怯。

我现在选型时的习惯是先问自己三个问题:这个任务是计算密集还是数据搬运密集?是不是对延迟敏感?WiFi 是不是必须同时开着?答案不同,对 ESP32 的态度就完全不同。如果你也想做一轮自己的性能实测,建议先把我上面说的几个变量控制好,否则测出来的数字很可能只对你自己那块板子有意义,换个环境就完全对不上了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询