
JEIOptimizer
15倍更快的JEI物品过滤构建——大幅减少大型模组服务器上“加入世界中...”的等待时间。
JEIOptimizer
并行构建 JEI 的物品筛选索引 —— 在大型模组包中可将加入服务器的时间缩短最多 17 秒。
背景
我和朋友在一个私有的 AllTheMods 服务器上玩。每次断线、每次重启、每次“我去拿点零食”,都意味着我要盯着 “正在加入世界...” 看 40 秒,而其他人早已开始挖矿。
受不了了。我花了整个周末打开 JEI 的源码,而不是玩游戏。这个模组就是由此诞生的。
功能
当你连接到一个有模组的服务器时,JEI 会从头重建它的整个物品搜索索引——因为服务器可能会提供自定义配方。在一个有 250 个模组、约 50,000 个物品的整合包中,这一过程会在 主线程上占用 12 秒以上。你的客户端就这么卡死了。
JEIOptimizer 将 JEI 的 IngredientFilter 构建过程并行化到工作线程上。每个搜索前缀(物品名称、模组 ID、标签、提示文本……)都有自己的线程,运行在独立的数据结构上——没有争用、没有竞态、没有风险。
实际测量数据
在 250+ 模组的整合包(AE2、Mekanism、Create、Cobblemon、Apotheosis、AllTheCompressed……)上测试。Ryzen 5600X · 10 个工作线程 · NVMe · 分配 8 GB 内存 · 远程服务器(Hetzner 数据中心)。
| 阶段 | 原版 JEI | + JEIOptimizer | 缩减幅度 |
|---|---|---|---|
| 构建物品筛选器 | 12.00 秒 | 0.79 秒 | −94%(15 倍快) |
| JEI 启动总计 | 25.84 秒 | 14.17 秒 | −45% |
| 总连接时间 | 约 40 秒 | 约 23 秒 | −42%(−17 秒) |
配合下面的额外优化(参见 免费再省 8 秒),你可以将服务器连接时间从 40 秒 稳定降到 约 23 秒。
工作原理(技术细节)
JEI 的 IngredientFilter 会构建一个搜索索引,其中每个“前缀”(名称、模组 ID、标签、提示文本……)都有自己的 GeneralizedSuffixTree。独立的结构 → 可以安全地并行构建。
原版 JEI:
遍历每个物品(50,000):
遍历每个前缀(7-10):
计算标记 → 插入后缀树
一个线程 = 约 12 秒。
JEIOptimizer:
对前缀进行 parallelStream:
遍历每个物品:
计算标记 → 插入自己的后缀树
6-10 核心同时处理 7-10 个前缀 = 约 0.8 秒。
筛选模式(配置中)
OFF— 原版 JEI 行为BATCH— 小幅度缓存友好改进,单线程PARALLEL_PREFIX— 按前缀并行构建(安全)PARALLEL_FULL— 在前缀内部也并行化标记计算(默认,最快)
免费再省 8 秒(手动 JEI 调整)
在 config/jei/jei-client.ini 中,改为:
tooltipSearchMode = DISABLED
JEI 每次连接时都会索引所有物品的提示文本。有些模组在提示文本渲染时会做大量 I/O 操作——吃掉了原本 12 秒中的约 8 秒,却毫无用处。玩家几乎总是通过名称搜索,而不是提示文本。
如果玩家想通过 #前缀 进行提示搜索,请改用 REQUIRE_PREFIX。
配置
config/jeioptimizer-client.toml(自动生成):
[filter]
mode = "PARALLEL_FULL" # 默认。安全,最快。
async = false # 实验性:后台构建
log_timing = true # 记录耗时供验证
worker_count = 0 # 0 = 自动(核心数 - 2)
[plugins]
parallel_phases = [] # 实验性——见下文
parallel_creative_tabs = false # 实验性——见下文
开箱即用的安全默认值。 放入 jar 文件即可生效。无需修改配置文件。
兼容性
- Minecraft: 1.21.1
- 模组加载器: NeoForge 21.x
- JEI: 19.x(1.21.1 版本)
- 运行端: 仅客户端——无需在服务器端安装
这不会加速什么
坦诚说明范围:
- ❌ 游戏启动(模组构造、模型烘焙、资源包重载)
- ❌ 服务器数据同步(配方、标签、注册表)——受限于网络和模组序列化
- ❌ 每个模组运行时数据重新生成——Create 每次连接会生成 2,124 个配方,Cobblemon 会重新同步所有化石/标记/浆果,Apotheosis 会重新加载所有词缀。这些是模组设计上的选择。
JEIOptimizer 将 JEI 从瓶颈中移除。它不再是短板——其他模组仍会做它们的事情。
实验性功能(默认关闭)
已在真实模组包上测试,但发现会破坏东西。适用于精心挑选的模组集合,可选择启用:
plugins.parallel_phases— 并行化插件配方注册。许多 JEI 插件(Theurgy、Ars Nouveau、Compact Machines)不是线程安全的,会崩溃。plugins.parallel_creative_tabs— 并行化创造模式标签页构建。许多模组以非线程安全方式缓存标签页状态;在我们的测试中,有 22% 的 JEI 物品丢失。filter.async— 在后台构建筛选器;玩家可更早进入世界。如果他们在前 2 秒内打开 JEI,会看到一个空白网格,直到准备就绪。
除非你知道自己在做什么,否则请保持关闭。
常见问题
问:这会破坏 JEI 搜索吗?
默认模式(PARALLEL_FULL)改变了索引的 构建方式,而非 构建内容。相同的物品、相同的配方、相同的搜索结果。
问:我用的整合包比较小。效果会差一些吗? 是的。在约 10,000 个物品以下,收益甚微。专为 30,000+ 物品的整合包设计。
问:为什么不为 JEI 提交 PR? 以后也许会。Mezz(JEI 的作者)历来偏好保守的改动——核心代码中的并行性可能不会被接受。这个模组的存在是为了让你不必等待上游。
问:需要在服务器端安装吗?
不需要。纯客户端 Mixin。将其放入服务器的 mods/ 文件夹不会有任何效果。
问:它与 EMI / REI 兼容吗? 不,这个模组专门针对 JEI。EMI 有自己的架构(而且已经很快了)。
致谢
在自定义 250+ 模组整合包以及 AllTheMods10、AllTheMons 上进行了测试。
感谢 Mezz 保持 JEI 源码的开放和可读性,使得外部优化成为可能。
正在加载版本记录…
正在加载评论…
评论在新手盒子客户端中发表,这里同步展示。