高频多线程下访问含两float的atomic struct与两个独立atomic float哪个效率更高
问题描述:此前在单线程中高频拉取传感器数据,部分测量场景采样间隔为1ms,也存在间隔2/5/10ms的场景,同时在同线程内完成界面展示(实时折线图/仪表盘)。为提升效率计划将逻辑拆分为两个线程,其中数据展示线程仅每20ms访问一次共享变量,请问对数据拉取线程而言,覆写两个独立的线程安全变量,和覆写一个包含这两个变量的struct/对象相比,哪种方案带来的延迟更低?
结论
对高频运行的数据拉取线程而言,覆写两个独立的线程安全变量延迟更低,在1ms级采样场景下差异可观测。
核心原因拆解
- 线程安全写入的核心开销来自内存屏障/原子操作的执行成本:两个独立原子变量的写入只需要触发两次轻量的单字原子操作,而要保证struct/对象整体写入的线程安全,绝大多数实现都需要加
mutex、读写锁等同步机制,锁的上下文切换、内核态调度开销远高于两次无锁原子写入的成本。 - 如果你尝试用无锁方案实现struct的整体原子写入,比如依赖x86平台的
CMPXCHG16B双字CAS指令,理论上可以做到一次原子更新整个结构体,但该操作本身的延迟就比两次独立的单字原子写高15%~30%,同时存在平台兼容性限制,实现复杂度也更高。 - 若你的业务场景不需要两个变量严格的时间一致性(即展示线程允许拿到「第一个变量是新采样值、第二个是上一次采样值」的组合),两次独立原子写的优势会进一步放大,甚至可以用
memory_order_relaxed内存序写入,延迟还能再降低。
适配你的场景的优化建议
- 你的展示线程仅20ms读一次共享变量,对拉取线程的写入干扰极低,优先选择两个独立的原子变量,写入用
memory_order_release、读取用memory_order_acquire即可满足一致性要求,不需要加任何锁。 - 如果后续需要保证两个变量的时间一致性(必须同时拿到同一采样时刻的两个值),可以额外加一个原子版本号字段,展示线程连续读两次版本号判断中间是否有写入即可,几乎不会增加拉取线程的写入开销。
内容的提问来源于stack exchange,提问作者knopele
相关产品推荐
相关产品推荐

