让我们从基本原则开始:你的导师告诉你的往往是完全倒退的。写入通常比读取快。具体来说(至少对于大多数现代 CPU),写入只是意味着将地址和值存入队列。然后 CPU 的其他部分可以处理将该值写入内存,而执行单元可以继续执行更多指令。但是,如果在写入队列已满时/如果您尝试写入更多数据,指令流可能会停止。
相比之下,要进行比较,如果数据尚未在缓存中,则必须将地址写入内存,然后停止直到数据从内存到达才能正确使用它进行比较。
比较还使用标志寄存器,它有很大的“寄存器压力”,因为大多数指令都会修改它们。这可以防止原本可用的指令级并行性。
现在,确实,您通常宁愿避免使用相关数据污染缓存,除非您很快会将其用于其他目的。一些缓存通过不在写入时分配缓存空间而完全避免了这种情况——即,除非您最近读取了数据,因此它已经在缓存中,否则写入它不会将其移动到缓存中;它只会将数据直接写入主存储器。
许多(大多数?)最近的处理器还具有始终直接写入内存的指令,而不管缓存策略如何。英特尔(例如)调用这些非临时存储(例如,MOVNTQ 和 MOVNTPS)。但是,正确使用这些可能有点棘手。与普通的内存写入不同,默认情况下它们不保证缓存一致性。您需要在写入后执行 SFENCE 指令,以确保其他处理器将看到写入的结果。
另一次值得进行比较的时候是单个比较可以让您避免大量写入。例如,假设您的数组非常稀疏,因此几百个条目中只有大约一个是非空的。在这种情况下,您可以(例如)使用位图,其中位图中的一位表示指针是否为空。在这种情况下,单个 64 位比较可以让您避免(例如)写入每个 64 位的 64 个不同指针中的任何一个。
不过,单独查看指针不会带来任何好处——具体而言,您需要先将每个指针加载到缓存中,然后才能进行比较,因此尝试逐个比较以避免污染缓存是一种弄巧成拙的主张。