写策略与一致性:写直达与写回,写分配与写不分配
好,咱们今天聊聊缓存写策略。这个话题,说白了就是CPU往缓存里写数据时,到底该怎么处理。你想想看,缓存是快的,内存是慢的,那数据写进去之后,两边不一致了怎么办?这就是一致性问题。
我在项目里见过不少同学,一上来就纠结选哪个策略。其实没那么玄乎。我们先搞清楚两个维度:写命中时怎么做,和写未命中时怎么做。
写命中策略:写直达 vs 写回
先看写命中的情况。也就是你要写的数据,已经在缓存里了。这时候有两种选择。
写直达(Write-Through)
写直达,顾名思义,就是数据同时写入缓存和下一级存储(比如内存)。
- 优点:实现简单,缓存和内存永远一致。你不用担心数据丢失。
- 缺点:慢。每次写操作都要等内存写完,写操作的延迟被拉长了。
我记得有一次做视频编解码芯片的优化,发现写直达导致整个流水线经常卡住。为什么呢?因为编码器写数据太频繁了,每次都要等内存,带宽根本扛不住。
写回(Write-Back)
写回就聪明多了。数据只写到缓存里,标记为“脏”(dirty)。等缓存行被替换出去时,才真正写回内存。
- 优点:快。写操作只到缓存就结束了,延迟极低。
- 缺点:实现复杂。需要维护脏位,还要处理一致性协议。
我建议,大部分通用计算场景,用写回就对了。你想想看,CPU写数据通常有局部性,写了一次可能马上又写第二次。写回能把这些写操作攒起来,一次刷回内存,效率高得多。
写未命中策略:写分配 vs 写不分配
好,现在看另一种情况。你要写的数据,缓存里没有。这时候怎么办?
写分配(Write-Allocate)
先把数据从内存加载到缓存,然后再写缓存。说白了,就是“先加载,再写”。
- 通常搭配写回使用。因为既然都加载进来了,后面可能还会写,用写回更划算。
- 优点:后续的写操作都能命中缓存,性能好。
- 缺点:第一次写未命中时,需要读内存,延迟较高。
写不分配(No-Write-Allocate)
不加载到缓存,直接写到下一级存储。缓存里还是没这个数据。
- 通常搭配写直达使用。反正每次都要写内存,何必多一步加载呢?
- 优点:避免缓存被污染。如果这个数据只写一次,以后再也不用了,那加载进来就是浪费。
- 缺点:后续再读这个数据,还是缓存未命中。
四种组合,一张表说清楚
| 写命中策略 | 写未命中策略 | 典型场景 | 我的建议 |
|---|---|---|---|
| 写直达 | 写不分配 | 控制寄存器、状态标志 | 简单场景首选 |
| 写直达 | 写分配 | 极少用,性能差 | 别这么配 |
| 写回 | 写分配 | 通用计算、AI推理 | 大部分情况选这个 |
| 写回 | 写不分配 | 流式数据、一次性写入 | 特殊优化场景 |
嗯,这里要注意。写直达+写分配这个组合,基本没人用。为什么呢?你想想看,写未命中时加载数据到缓存,然后写直达又把数据刷回内存。缓存白加载了,还多了一次读内存的开销。纯属浪费。
核心逻辑图:写策略决策树
下面这张图,是我自己画的一个决策流程。你写代码或者配硬件时,可以照着这个思路走。
实际项目中的选择建议
我个人习惯,拿到一个算子映射任务时,先问自己三个问题:
- 这个数据写完之后,还会再读吗? 如果会,用写分配+写回。如果不会,考虑写不分配。
- 写操作的频率高吗? 频率高,用写回。频率低,写直达也可以接受。
- 一致性要求有多严格? 如果其他核或设备需要立即看到最新数据,写直达更安全。
嗯,最后说一句。写策略没有绝对的好坏,关键看你的数据访问模式。我见过有人把写回用在一堆只写一次的数据上,结果缓存污染严重,性能反而下降。也见过有人死守写直达,结果带宽被打满,整个系统卡成PPT。
理解你的数据,比死记硬背策略更重要。
想要更多资料,联系可可