java - 了解异步 Logger 中的环形缓冲区
解决方案
环形缓冲区中的插槽数必须是 2 的幂。这允许您不断递增计数器并使用位掩码而不是模数从计数器获取数组索引。
例如,假设我们有一个大小为 4 的环形缓冲区。索引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 的倍数。
回到问题: ringbuffer 中的实际插槽数是262144
. 文档256 * 1024
说明这是 2 的幂。
推荐阅读
- c# - 带有 Sendgrid 的 ASP.NET Core 2 EmailSender 异常
- java - 如何在Android中使用线程每秒运行代码
- java - Firebase - 按值将数据检索到外部变量
- php - PHP CodeIgniter - 如何为网站根目录设置默认页面
- trace32 - 将所有函数符号及其基地址转储到 trace32 中的文本文件
- python - 预测另一个列表的对应列表时应采用什么形状的数据
- arrays - 通过 Postman 发送 JSON 会导致我的 Node.js 服务出错
- machine-learning - 什么是 epsilon/k 它是如何出现在 epsilon 贪心算法中的
- python - SymPy dsolve 为数学等效的微分方程返回不同的结果
- mysql - 使用 Laravel 查询 sql 中的 json 列