答案 0 :(得分:2)
环形缓冲区中的插槽数量必须是2的幂。这允许您继续递增计数器并使用位掩码而不是模数来从计数器获取数组索引。
例如,假设我们有一个大小为4的ringbuffer。索引0
到3
是数组的有效索引。我们希望避免检查index++; if (index > 3) { index = 0; }
。在紧密循环中,if
检查可以减慢速度。我们可以避免吗?
是的,我们可以。我们可以在不检查的情况下递增,当我们从数组中获取值时,我们忽略所有4的倍数(数组的大小)。通常人们会使用模数操作:value = array[index % 4];
3 % 4 = 3
4 % 4 = 0
5 % 4 = 1
...
这很好,但我们可以做得更好。模运算适用于任何数组大小,但我们选择数组大小为2的幂,原因如下:位掩码!位掩码可以实现相同的功能,但速度要快得多(大约快25倍)。
这是如何工作的?如果数组是2的幂,我们通过减去1得到它的位掩码。然后,我们从数组中获取值时使用此掩码:value = array[index & mask];
对于4,位掩码是4-1 = 3。二进制表示法中的3是11
。让我们看一下与以前相同的例子:
0011 & 0011 = 0011 (3 & 3 = 3)
1000 & 0011 = 0000 (4 & 3 = 0)
1001 & 0011 = 0001 (5 & 3 = 1)
...
所以这与采用模数但速度更快相同。同样,关键点是数组需要是2的倍数。
回到问题:环形缓冲区中的实际插槽数为262144
。文档陈述256 * 1024
以澄清这是2的倍数。