写点什么

瞧不上 C++ 和 D 语言,国外程序员将 5.8 万行代码迁移到 Jai 语言,到底图什么?

  • 2022-12-02
    北京
  • 本文字数:3633 字

    阅读完需:约 12 分钟

瞧不上 C++ 和 D 语言,国外程序员将 5.8 万行代码迁移到 Jai 语言,到底图什么?

本文中,我将向大家分享自己把游戏开发成果移植到 jai 语言的经历。我的游戏之前主要是用 D 和部分 C_++ 编写的,总代码有 58620 行(不包括库)。其实这事我已经筹划了很久,还专门记录下了最初的期望、移植过程和最终结果。下面,就请大家随我一道回顾这段历程。


为什么要移植


很多朋友可能好奇,为什么会有人要大费周章把这么些代码移植成另外一种语言?把项目做完,之后再用新语言不好吗?我当然有自己的考虑,主要基于以下几点:


  • 现状让我的日常工作非常痛苦

  • 我有称手的系统移植工具,所以移植过程应该会比较顺利

  • 对我来说,Jai 似乎比 C++ 或者 D 更有吸引力


为什么不用 C++


网上关于 C++ 缺点的讨论已经很多,所以这里不再赘述。简而言之,C++ 几十年发展下来积累了太多错误决策,而且永远都摆脱不掉了。它的标准库堪称灾难,代码几乎不可能在交给他人后顺利运行。而且不知道为什么,C++ 每次新增功能都有坑。所以 C++ 的使用感受确实很差,时时刻刻在折磨着我,而且这个项目的发展方向在我看来也有问题。总之,我想尽快离开 C++ 生态系统。

为什么不用 D

我的游戏开发之旅始于 2019 年,当时我已经感受到 C++ 的问题了,但并不知道哪种语言更好。于是我选择了 D,理由如下:它很像 C++,只是去掉了不好的部分。但很遗憾,这只是我的一厢情愿,D 在很多方面都跟 C++ 一个德行。


必须承认,D 跟 C++ 比确实有一些优势,比如更强大的元编程、无需标头、没有未初始化的值等。但很遗憾,这些优点根本就抵消不掉现实缺陷。


我在 Windows 上的两种 D 编译器(dmd 和 ldc2)之间反复横跳了四年,最后发现至少在 Windows 平台上,D 语言的状态也就是个业余项目、往好听了说也是极不成熟的水平。很难相信这是种已经发展了 20 多年的语言。截至目前,我不建议任何人在 Windows 上用 D 开发严肃项目,甚至还不如继续用 C++。从我亲身经历的问题来看,目前最大的麻烦是 Windows 上的调试信息完全 损坏:


  • 在 90% 的情况下,this 指针会缺失或出错

  • 函数堆栈上的变更经常部分 / 完全丢失或出错

  • 有时会报告变量值错误,但却没有任何其他可见的问题

  • 静态 foreach 扩展处理不当,令调试工具无所适从

  • minxins(相当于 D 中的宏)生成的调试信息会令调试工具找不到正确文件(只能按步进行反汇编)

  • 在 Visual Studio 中将指令指针移回上一行,经常导致程序在执行下一条指令时崩溃在 D Language Code Clulb 讨论版上,我看到“DMD 以往曾经出过很多关于调试信息的问题”,但号称正在处理中。可很遗憾,ldc2 也根本没好到哪去。而且除了调试之外,元编程这边也有不少缺点和问题:

  • 不同的编译器阶段会诡异地相互影响,导致元编程出现意外,引发误导性错误

  • ldc2 的编译速度非常慢,但我别无选择,因为 dmd 有 bug

  • D 提供所谓 betterC 模式,其中禁用垃圾收集;但在使用此模式时,标准库不编译而且元编程也会受到严重阻碍

  • 说明文档缺失

  • 还有其他几十个更具体的问题


总而言之:虽然 D 在某些方面确实比 C++ 强点儿,但其他地方的问题反而更多,导致使用体验痛苦万分。其中最大的问题就是糟糕的调试信息和极具破坏力的垃圾收集机制。我承认,我只是想把 D 当成改进版的 C++ 来用,而 D 的开发者并不认同这种理解。所以 D 不适合我,而且我现在根本就不敢信任它的调试器。


为什么选择 Jai


种种遭遇,把我引向了 Jai。这是 Jonathan Blow 从 2014 年开始开发的一种语言,而且直到 2019 年 12 月才向编译器敞开大门。目前封闭测试仍在进行中,我也是约两个月前受邀体验的一员。Jai 的诞生源自 Blow 对 C++ 的失望。而且跟 D 不同,Jai 确实朝着我所认可的、能够对 C++ 做出有意义改进的方向前进。在我看来,Jai 的最大优势有二:更快的编译速度,还有以不受限制的编译时执行进行元编程。


值得注意的是,这里讨论的可不是编译速度提高 20%、或者元编程功能选项略有增加之类不痛不痒的小改进。Jai 的编译速度提高了 10 到 100 倍,而且能在编译期间执行任何操作。特别是与编译时编译器 API 相结合的元编程,已经带来了具有深远意义的影响:例如消除对构建系统的需求,也摆脱了对复杂的非启发式自定义检查的依赖。除此之外,Jai 还对 C++ 做出了其他改进,例如更好的默认值、更简单的语法、更实用的标准库、命名函数参数、上下文、using 等。这就让我有了信心,打算通过从 D 移植到 Jai 让自己的游戏获得以下收益:


  • 将编译时间从现在的 60 秒左右降低到 5 秒以内,最好能达到 1 秒上下

  • 调试器终于能用了 

  • 用 Jai 代码替代了 build-script

  • 用元编程引入自定义编译检查,借此捕捉更多错误

  • 用更简单的命令式代码替代复杂的元编程代码

  • 提供一系列语法改进,减少了代码中的噪声

  • 删除了以往使用多种语言时无法避免的重复部分 ##

    为什么不考虑其他语言


的确,我明确不想用的只有 D 和 C++,而略感兴趣的是 Jai……那为什么不试试别的语言呢?


最无法回避的选项应该就是 Rust 了。它风头正劲、社区活跃,但我还是感觉 Rust 在设计权衡方面有点问题。支持 Rust 的开发者们似乎有种“内存安全是第一要务”的集体心态。没错,很多问题都源自内存安全问题,所以我大体能够理解这样的判断。但也有很多对于安全和质量要求没那么极端的软件需求。


比如,我相信如果 C 和 C++(基本就是公认的「最不安全」语言)能够去掉零终止字符串、默认初始化值和适当的指针 + 长度类型,那就足以用边界检查取代 90% 的指针算法、解决临时内存管理的需求了。另外,我觉得很多人在追求“安全”代码时,其实是忽略掉了软件漏洞层出不穷的根本原因:文化上对于复杂性的容忍,甚至是鼓励 14。总之,我不愿意忍受 Rust 那漫长的编译时间,也不太认同它的文化定位。跟 Rust 不同,jai 就很关注如何控制复杂度,这一点更符合我自己的文化判断。


还有其他一些人气稍逊的选项,例如 Zig。我只能说它们可能也有巨大的潜力,但我不太相信这些会是正确的选择。不是好或者不好,只是没那么强的吸引力。


如何移植


刚开始,我还在心里给自己鼓劲、祈祷移植过程能顺利完成。之所以比较乐观,是因为我在游戏中设置了两套有助于移植的系统:


  • 游戏会将游戏会话的输入(HID、加载文件、网络等)记录到文件内并稍后重播。在重播时,记录的输入输出确定性能让游戏循环达到完全相同的状态,精确无误。

  • 游戏在执行过程中的各个点位上,都会对游戏状态进行哈希处理,并将相应的哈希值保存在不同文件当中。这样在重播时,文件内容即可用于检查重播是否跟原始执行完全匹配。


这两项功能间有一些细微差别,但对整体运行影响不大。依托这些功能,我的移植计划如下:


  • 将一小段代码由 D 或 C++ 复制到 jai,而后编译。

  • 调用新的 jai 代码,替代旧有 D 或 C++ 代码。

  • 重播录制的游戏会话。

  • 如果重播发生分歧,则说明移植引入了 bug,修复此 bug。

  • 如果重播无分歧,则移植成功,继续下一步。


这种方法的关键在于:


  • 是不是所有引入的 bug 都会导致游戏状态发生显著分歧?

  • 代码能否以较小的增量进行移植,以便易于知晓 bug 存在、找到 bug?


第一个问题,取决于状态哈希覆盖到多少代码。有些代码需要知晓游戏是否正在重播,这些部分的内部行为会有所不同,因此无法得到有意义的哈希值。例如,写入文件功能会在重播时丢弃一切数据,因此如果移植后的写入文件中出现了 bug,就会被哈希过程注意到。幸运的是,大部分代码并不属于这一类。最初的哈希在代码库中极少被用到,但最近我开始将其扩展到插入动态数组的过程,例如记录动态数组的大小和容量。


如此一来,当有 bug 导致动态数组的插件会改变游戏逻辑时,问题就会被及时注意到。因为我代码中的几乎所有功能都是靠动态数组实现的,所以即使是在任何庞大而复杂的数学算法当中,每一点微波的行为变化都能引起注意。


第二个问题则属于经典编程问题:你的代码解耦程度到底有多高?这一点非常有趣,因为我得把代码库里的所有偶发复杂性元素找出来。首先就是模板函数:它们无法直接移植,因为函数定义和调用站点必须在同一编译器之内,才能让模板正常起效——除非对模板进行手动实例化。我的代码库里有不少模板化代码,但它们跟容器和序列化没什么紧密关联,所以我觉得这应该不会惹出太大的麻烦。


继续推进


下面来点更直观的统计数据和图片吧。先来看我这代码库的当前状态:



总体来说,这里有 45701 行 D 代码和 12919 行 C++ 代码,总共 58620 行。编译时间如下:



在调试模式下,ldc2 的编译过程大概需要 3 分钟,最高占用 8 GB 内存。这时候如果打开浏览器,那我这台 16 GB 内存的笔记本电脑就会进入满负荷运行。发布模式内存占用量更大,为 11.5 GB。




如果一切顺利进行,那在两张图中,一切现有色块都应该会被新色块取代。能成功吗……


最后,我想用数字来解释移植的收益,特别是我当初的预期错得有多离谱:


  • 我预计整个过程需要 160 个小时(每周 40 小时,共耗时一个月)。但我这个估计差得太多了,很可能根本用不上一个月的时间。

  • 我希望编译时间能从 1 分钟左右下降到最多 5 秒,能到 1 秒上下最好。至于移植后的最终结果如何,我将持续保持更新。


原文链接:

https://www.yet-another-blog.com/porting_the_game_to_jai_part0/

2022-12-02 16:215178
用户头像
李冬梅 加V:busulishang4668

发布了 965 篇内容, 共 563.4 次阅读, 收获喜欢 1120 次。

关注

评论

发布
暂无评论
发现更多内容

【干货】验证码的常见类型总结

宙哈哈

php html 验证码 短信验证码

2023Java岗面试,进互联网大厂必备Java面试八股文真题解析

程序知音

Java java面试 后端技术 八股文 Java面试八股文

基于 Nginx&Lua 实现自建服务端埋点系统

亚马逊云科技 (Amazon Web Services)

Amazon

联合解决方案|亚信科技AntDB携手蓝凌软件,助推企业数字化办公转型升级

亚信AntDB数据库

AntDB AntDB数据库 企业号 4 月 PK 榜

从逻辑到硬件:如何转换PCB布局?

华秋PCB

工具 电路 PCB PCB布局 PCB设计

恶意爬虫?能让恶意爬虫遁于无形的小Tips

宙哈哈

Python html nginx 爬虫

长安信托:拥抱数字信托,探索多项目管理新路径

万事ONES

关于验证码,你不知道的一些问题!

宙哈哈

php html 记录 验证码

深入探索Go语言的unsafe包,揭秘它的黑科技和应用场景!

王中阳Go

golang 高效工作 面试题 黑科技 Go 语言

Higress GitHub star 突破 1k,来自社区开发者和用户的寄语

阿里巴巴云原生

阿里云 云原生 Higress

AntDB数据库携超融合流式实时数仓亮相第25届中国高速公路信息技术化大会

亚信AntDB数据库

AntDB AntDB数据库 企业号 4 月 PK 榜

软件测试/测试开发丨两个步骤轻松搞定测试环境问题

测试人

软件测试 自动化测试 测试开发

架构训练营模块二作业

请叫我馒头哥丶

架构实战营

远程调试为何要亲历现场,也许也可以这样解决

石臻臻的杂货铺

远程调试

深度学习基础入门篇[二]:机器学习常用评估指标:AUC、mAP、IS、FID、Perplexity、BLEU、ROUGE等详解 1.基础指

汀丶人工智能

人工智能 机器学习 深度学习 算法评价指标

AI开发实践:关于停车场中车辆识别与跟踪

华为云开发者联盟

人工智能 华为云 华为云开发者联盟 企业号 4 月 PK 榜 车辆检测

autodesk maya 2023最新中文版 Maya动画和建模软件

理理

Autodesk Maya maya破解版 玛雅2023下载

SketchUp Pro(草图大师2023)中文版 Mac/win

理理

SketchUp Pro 2023 SketchUp Pro中文版 草图大师2023下载

MobTech MobLink|无码邀请是怎么处理的

MobTech袤博科技

目前led显示屏厂家存在的问题

Dylan

制造 行业 LED显示屏

JetBrains CLion 2023中文版安装教程CLion 2023新功能

理理

C/C++ CLion 2023 JetBrains CLion破解版

Excelize 入选 2022 中国开源创新大赛优秀项目

xuri

golang 开源 Go 语言 Excelize OOXML

Ample Sound Ample Bass Upright III Mac(虚拟立式低音乐器)

理理

基于 Flink ML 搭建的智能运维算法服务及应用

Apache Flink

大数据 flink 实时计算

2023年成都.NET线下技术沙龙来了!大咖分享,报名从速

MASA技术团队

.net dapr MASA

从零学习SDK(2)SDK的基本概念和组成部分

MobTech袤博科技

Autodesk AutoCAD 2024 Mac(cad2024) v2024.3 支持M1 兼容Mac13系统

理理

mac软件下载 M1芯片 cad2024激活版 Autodesk AutoCAD

局域网IP扫描软件:IP Scanner Pro激活版

真大的脸盆

Mac IP 局域网管理 IP扫描工具 局域网扫描

建木在 Rainbond 上使用实践

北京好雨科技有限公司

云原生 CI/CD #Kubernetes# rainbond 企业号 4 月 PK 榜

解决Parallels Desktop 18.2.0提示“由于临界误差,不能启动虚拟机”的问题

理理

Parallels Desktop 18 pd18虚拟机 PD虚拟机不能联网

瞧不上 C++ 和 D 语言,国外程序员将 5.8 万行代码迁移到 Jai 语言,到底图什么?_编程语言_Simon van Bernem_InfoQ精选文章