我们在Swoole
源码里面会看到很多的likely
和unlikely
宏,例如在创建协程的时候,有如下代码:
1 | long cid = PHPCoroutine::create(&fci_cache, fci.param_count, fci.params); |
这里,Swoole
调用PHPCoroutine::create
来创建协程,并且返回了协程的id
。然后,接着是对cid
使用了宏likely
。这个用法是为了提升CPU
指令缓存的命中率。
CPU
缓存是几块离CPU
近的存储空间。CPU
通常分为三级缓存(不是代表只有三块缓存,而是等级有三类)。我们可以通过一下命令来查看CPU
缓存的大小:
1 | [root@bceb11389603 test]# lscpu | grep cache |
可以看出,我的机器上有四块CPU
缓存,其中有两块L1
缓存,大小是32K
;一块L2
缓存,大小是256KB
;一块L3
缓存,大小是4096KB
。
我们发现,L3
缓存要比L1
、L2
级缓存大很多,因为现在的CPU
都是多核的,每个核都有自己的L1
、L2
级缓存,但L3
级缓存却是同一颗CPU
上所有核心共享的。程序执行时,会先将内存中的数据载入到共享的L3
级缓存中,再进入每颗核心独有的L2
级缓存,最后进入最快的L1
级缓存,最后才会被CPU
的核使用。
那么为什么有两个L1
级缓存呢?因为CPU
核会对指令与数据进行区分。指令会放在L1
级指令缓存中,而指令所需要的数据放在L1
级数据缓存中。
所以,我们前面所说的likely
核unlikely
实际上就是为了提升指令缓存的命中率。而likely
和unlikely
宏是编译器为我们提供的显式预测分支概率的工具。实际上,CPU
自身的条件预测已经非常准了,仅当我们确定CPU
条件预测不准,且我们能够知晓实际概率时,才需要加入这两个宏。
如果我们需要查看指令缓存的命中率,我们可以通过perf这个工具来查看