1BRC
1️⃣🐝🏎️ 十亿行挑战 -- 一个有趣的探索,看看能以多快的速度从文本文件中聚合10亿行数据。这个挑战主要针对Java,但我决定用Golang来解决它!
我写了一篇详细的博客介绍我的实现方法,你可以在这里查看。
迭代记录
最终实现方法如下图所示:
以下是每次迭代的详细记录:
尝试次数 | 方法 | 执行时间 | 差异 | 提交 |
---|---|---|---|---|
0 | 朴素实现:将温度读入城市的映射中。串行遍历映射中的每个键(城市)以找出最低、最高和平均温度。 | 6:13.15 | ||
1 | 使用goroutines并发评估映射中的每个城市。 | 4:32.80 | -100.35 | 8bd5f43 |
2 | 移除对float64切片的排序。通过迭代计算最小值、最大值和平均值。 | 4:25.59 | -7.21 | 830e5df |
3 | 解耦文件内容的读取和处理。使用缓冲goroutine在两个进程之间通信。 | 5:22.83 | +57.24 | 2babf7d |
4 | 不再向通道发送每一行,而是每100行一起发送。此外,为了最小化垃圾回收,重置切片时不释放内存。 | 3:41.76 | -161.07 | b7b1781 |
5 | 以100 MB的块读取文件,而不是逐行读取。 | 3:32.62 | -9.14 | c26fea4 |
6 | 将温度从string 转换为int64 ,以int64 处理,最后转换为float64 。 | 2:51.50 | -41.14 | 7812da4 |
7 | 在城市<>温度映射中,将每个键(城市)的值替换为预处理的最小值、最大值、计数和所有温度之和,而不是存储该城市的所有记录温度。 | 1:39.81 | -71.79 | e5213a8 |
8 | 使用生产者消费者模式分块读取文件并并行处理这些块。 | 1:43.82 | +14.01 | 067f2a4 |
9 | 通过将每个读取的块处理成一个映射来减少内存分配。结果通道现在可以整理较小的已处理块映射。 | 0:28.544 | -75.286 | d4153ac |
10 | 通过在处理城市温度时不读取小数点来避免字符串连接开销。 | 0:24.571 | -3.973 | 90f2fe1 |
11 | 直接将字节切片转换为字符串,而不使用strings.Builder 。 | 0:18.910 | -5.761 | 88bb6da |
12 | 用自定义的string 到int 解析器替换strconv.ParseInt 。 | 0:14.008 | -4.902 | 17d575f |
13 | 在构建最终结果字符串时减少映射访问调用。 | 0:12.017 | -1.9991 |