一、前言
2024年元旦起,此挑战正式开放提交,截止日期为2024年1月31日。2024年1月31日23:59 UTC之后创建的提交(即拉取请求)将不予考虑。
“十亿行挑战”(1BRC)是一个有趣的探索,旨在测试 Java 从文本文件中聚合十亿行数据的能力。动用你所有的(虚拟)线程,使用 SIMD 技术,优化垃圾回收,或者尝试其他任何技巧,创建最快的实现方案来解决这个任务吧!
二、挑战内容
图片
文本文件包含了一系列天气站的温度值。每一行都是一个测量结果,格式为<string: 站点名称>;<double: 测量值>
,其中测量值恰好有一位小数。以下是一个示例,展示了十行数据:
Hamburg;12.0
Bulawayo;8.9
Palembang;38.8
St. John's;15.2
Cracow;12.6
Bridgetown;26.9
Istanbul;6.2
Roseau;34.4
Conakry;31.2
Istanbul;23.0
任务是编写一个Java程序,该程序读取文件,计算每个气象站的最低、平均和最高温度值,并将结果按照站点名称按字母顺序排列,并以格式<最低温度>/<平均温度>/<最高温度>的方式输出到stdout(即标准输出),并将结果保留一位小数。
{Abha=-23.0/18.0/59.2, Abidjan=-16.2/26.0/67.3, Abéché=-10.0/29.4/69.0, Accra=-10.1/26.4/66.4, Addis Ababa=-23.7/16.0/67.0, Adelaide=-27.8/17.3/58.5, ...}
注意:必须使用 Java 21
三、运行挑战
1brc 代码库包含两个程序:
- dev.morling.onebrc.CreateMeasurements (通过 create_measurements.sh 调用): 在此项目的根目录中创建带有可配置数量的随机测量值的
measurements.txt 文件。 - dev.morling.onebrc.CalculateAverage (通过 calculate_average.sh 调用): 计算 measurements.txt 文件的平均值。
执行以下步骤来运行挑战:
- 使用Apache Maven构建项目:
./mvnw clean verify
- 创建 1B 行测量文件(仅运行一次):
./create_measurements.sh 1000000000
这将需要几分钟。注意:生成的文件大小约为 12GB,请确保有足够的磁盘空间。
- 计算平均测量值:
./calculate_average.sh
提供的简单示例实现使用Java流API来处理文件,并在用于结果评估的环境中以约2分钟完成任务。它作为比较自己实现的基线。
- 进行优化:
调整 CalculateAverage 程序以加快速度,使用任何你认为合适的方式(只需遵循下面描述的几个规则)。选项包括并行化计算、使用(孵化中的)向量API、同时内存映射文件的不同部分、使用AppCDS、GraalVM、CRaC等加快应用程序启动速度的工具,选择和调整垃圾收集器等等。
四、规则和限制
- 可以使用以下任何Java发行版:
SDKMan 提供的任何构建
openjdk.net 上可用的早期访问版本(包括Valhalla等OpenJDK项目的EA版本)
builds.shipilev.net 上的构建。如果要使用这些渠道不可用的构建,请联系讨论是否可以考虑。
- 不得使用外部依赖库
- 实现必须使用单个Java源文件
- 计算必须在应用程序运行时进行,即不能在构建时处理测量文件(例如,当使用GraalVM时)并将结果直接嵌入到二进制文件中
输入值范围如下:
- 站点名称:非空的UTF-8字符串,最小长度为1个字符,最大长度为100个字符
- 温度值:非空的double值,介于-99.9(含)和99.9(含)之间,始终带有一位小数
- 实现不能依赖于给定数据集的特定情况,例如必须支持根据上述约束条件的任何有效站点名称和任何数据分布(每个站点的测量次数)
五、参加挑战
要将您自己的实现提交给1BRC,请按照以下步骤操作:
- 创建 1brc GitHub 存储库的 fork。
- 创建 CalculateAverage.java 的副本,命名为 CalculateAverage_<your_GH_user>.java,例如 CalculateAverage_doloreswilson.java。
- 使该实现变得快速。真的很快。
- 创建 calculate_average.sh 的副本,命名为 calculate_average_<your_GH_user>.sh,例如 calculate_average_doloreswilson.sh。
- 调整该脚本,以引用您的实现类名。如果需要,在该脚本中通过 JAVA_OPTS 变量提供任何 JVM 参数。
- OpenJDK 21 是默认选项。如果需要使用自定义 JDK 构建,请在应用程序启动之前的启动 shell 脚本中包含 SDKMAN 命令 sdk use java [version]。
- (可选)如果您想要使用原生二进制文件(GraalVM),请调整 pom.xml 文件以构建该二进制文件。
- 针对上游存储库创建一个拉取请求,明确说明
您的实现类的名称。
程序在您的系统上的执行时间以及相应的规格(CPU、核心数、RAM)。这仅供参考,官方运行时将如下所述确定。
如果您想与社区讨论有关实施1BRC的任何潜在想法,可以使用此存储库的 GitHub 讨论。请保持友好和文明。
六、评估结果
结果是通过在 Hetzner Cloud CCX33 实例(8个CPU,32 GB RAM)上运行程序来确定的。时间程序用于测量执行时间,即测量整个时间。每个竞争者将连续运行五次。最慢和最快的运行将被丢弃。剩下三次运行的平均值是该竞争者的结果,并将添加到上面的结果表中。用于评估所有竞争者的完全相同的 measurements.txt 文件。如果您想在Hetzner Cloud上自行测试,请使用这些设置脚本(基于Terraform和Ansible),可能会对您有所帮助。请注意,这将产生费用 :)
图片
项目地址:https://github.com/gunnarmorling/1brc 快来挑战吧!