MoreRSS

site iconWincer修改

开发者、博主,喜欢研究新技术并在项目中实践,关注生活质量。博客内容广泛,技术、感想、日常吐槽皆有。
请复制 RSS 到你的阅读器,或快速订阅到 :

Inoreader Feedly Follow Feedbin Local Reader

Wincer的 RSS 预览

「消失」的表达欲

2026-09-26 18:34:41

cover

曾经的我很喜欢写文章,迫切地想把内心的想法和学到的新东西写在博客上:最开始的几年,我什么鸡毛蒜皮的事情都会写篇博客(还有二十多篇被我隐藏了起来)。后来工作了,这股热情很快消减下去,当时的我把它归咎于外部环境。

三年前离职后,我就没有再上过班,可这几年,这种情况并没有随着工作压力的消失而好转。我也可以再把它归咎于生活上的压力,但它究竟怎样影响了我的表达,我也说不清。叠加最近 AI 的高速发展,置身其中的我,已经很久没有体验过研究新技术、写代码、修 bug 时的心流了。

但我明明还有东西想说。写最近这几篇文章时,我总是在触及自己的情绪时浅尝辄止。我一直以为,是我积攒的东西太多:越久没有说,越想把积攒的一次性说清楚;写到一半突然卡住,又不知道该从哪里继续,最后只好把文章放回草稿箱,继续留给下一次。

写到这里,我又不知道该怎么继续了。但没关系,这次我会尽可能把我能写的写出来。


嫌疑人 1:工作

写 2019 · 终焉 的时候,是我情绪最饱满的时候,对领导、对工作、对公司的厌恶几乎要从字里行间溢出来。当时我把博客停更的根本原因归于工作氛围,这在当时的确是我最直接的感受。

刚出社会的第一份工作里,我一天绝大多数的清醒时间都耗在工位上,同事、领导之间的氛围也十分紧张。我印象特别深刻,当时的领导宣布 996 后随即对我们的工位进行了调整,原本的工位比较宽,他改成了让两个人坐同一个工位:一位开发配一位测试,像学生时代的同桌一样,个人空间被压缩,带来的是心理上的压迫感。

但换了一份按时下班的工作之后,我也并没有找回写文章的热情。2021 到 2022 这两年,我只写了 7 篇文章,是产出最少的两年。所以嫌疑人 1 其实是由两份工作共同组成的:第一份工作的氛围令人恶心;第二份工作的前半段几乎挑不出什么毛病,我却依然没有写出更多东西。或许那份工作真的耗费了我太多精力,让我无暇去思考别的事情。

嫌疑人 2:收入与不确定性

2025 年 9 月,我在 写给 28 岁的自己 里写过:工作不只提供工资,还带来社会身份与地位的认同感;没有工作之后,焦虑会从时间的稀缺,变成对金钱和前途的不确定,这种转变大约半年会稳定下来。现在读来,我依然十分认同。

2023 年 5 月 19 日离职后,整个 2024 年我都陷在这种「不确定」之中,离职后我拥有大把的时间,没有工作的压力,也没有讨厌的工作内容——这才是最难办的。它不像嫌疑人 1 那样始终看得见、摸得着,而是一团萦绕在身边的迷雾,始终无法摆脱。

当时的我不知道未来的收入来自哪里,我努力地想去找一个能持续性产生收入的渠道:接过软件外包,做过自媒体视频,想过用 AI 做什么软件解决用户痛点,参加过创业大赛等等,但都失败了;你看,我有很多经历可以说,但是我不想说了,不是我有更紧要的事情,更像是,我少了想把这些表述出来的冲动。

没过多久,我在 web3 赚到了第一桶金,收入超过了上班的时候。那些接外包、参赛的经历,也从「不想说」变成了「不必说」——它们已经无关紧要了。但这不是表达的冲动回来了,更像是表达的冲动换了对象。

但赚钱后仍然存在的不确定性,产生了新的表达需求:我清楚地知道,当时这笔收入不具备可持续性,但我又明白坐班的工作绝对不是我想要的。

直到现在,我仍没有完全摆脱嫌疑人 2 的影响。我甚至会想,它是不是早就藏在嫌疑人 1 之中:一个在明,一个在暗,而当时我的注意力全被明处的那个吸引走了。

嫌疑人 3:AI

我已经不记得上一次打开编辑器,思考如何实现一个功能,然后对着屏幕敲下代码,是什么时候了。AI 剥夺的不只是写代码时的心流,还有我的表达欲。以前我可以随手写技术文章,记录自己研究的技术、解决的 bug、折腾的过程;现在显然做不到了,因为这些过程已经不存在了。我只需要打开 Codex,把模型切换成 GPT-6 Astra,敲下指令,然后验收。

用 AI 之前,钻研问题时我常常能进入心流,无论是写作还是写代码。而我上一次进入心流,不是在写作或写代码时,而是去年装修的时候:我给一块 1.6m × 0.8m 的实木桌板刷水性漆,拿着刷子先蘸一点漆,滴在木板上,再顺着纹理朝一个方向慢慢刷匀。这很像古法编程:调 bug 的时候,思路、手指和屏幕连成一线,整个人都陷在问题里。

与之相比,我最讨厌的是装柜子和柜门:搬椅子、找钻头、钻孔、对孔位、拧五金,发现孔位没对齐,拆了重来。每一步都要重新调动注意力,还伴随着身体的费力和出错的焦躁。刚准备装上轨道,却发现有颗螺丝没对齐——这不就是我现在用 AI 时的样子吗?

表达的三个环节

审完三个嫌疑人,我慢慢觉得:有没有东西想表达,和最终能不能表达出来,中间至少隔着两层。表达本身是三个环节:有没有东西想说,有没有冲动说出来,能不能把它说成语言。三个嫌疑人,分别卡在了不同的环节上。

第一个环节,有没有东西想说,卡住它的是 AI。以前的技术文章,写的是我研究一个问题、修一个 bug 的过程,而现在,这个过程压根没有在我脑子里发生过。我只是描述需求,然后验收。没有研究技术的经历,自然也就没有东西可写。

第二个环节,有没有冲动说出来,卡住它的是工作。高压之下,大部分精力都耗在了内耗里。工作中学到的东西不是没有,但下了班,比起把它整理成一篇文章,我更想冲个热水澡、看部电影。东西还在,冲动先没了。

第三个环节,能不能把想说的组织成语言。我原以为,卡住自己的是收入和不确定性:我不知道该怎样描述现在的生活。

过去三年,每次朋友聚会聊到我在做什么,我都不知道该怎么说。最开始我说在休息,后来改口成创业,再后来改口成投资,我在同学面前的身份也变成了「已经财富自由的人」。我没法像大部分打工的人一样,随口说一句「我在上班」。

在父母亲戚面前也是这样,我只和他们说了和几个朋友开了个工作室,接外包。两周前的一个晚上,父母喊我吃饭,我正盯着 LP 仓位怕出差错,应了一声说待会来。大约十分钟后,我撤出仓位去吃饭,我爸已经快吃完了。

「是这个客户比较不好说话吗?这么忙,连吃饭都没时间。」

我愣了两秒,脑子里闪过一个念头:要不要告诉他,早就没有什么客户了,那我是不是又要解释什么是区块链,什么是 LP,赚的钱怎么换成法币?于是话到嘴边,还是变成了:「不是客户,是我们团队内部在讨论。」

我能分别说出这些事实,却还不能确定它们之间是什么关系。我说不清的,是对未来收入的焦虑,还是需要一个让自己和别人都能理解的身份?每一个都像是答案,又不完全是。那天晚上的两秒让我意识到,至少那一次,我并不是组织不出语言。那句「早就没有什么客户了」已经到了嘴边,是我自己把它换掉了。

嫌疑人 4:我自己

话还没出口,我就已经在考虑对方会怎样理解,于是换了一种说法。回看之前的很多文章时,我发现自己很早之前就会这样:情感还没有表达完,就先考虑读者的反应,有意按下了「暂停键」。当时的想法是:这是公开的文章,太强烈的情感或许会让读者反感。于是 2019 · 终焉 开头挂了一个 WARNING,结尾又反省是不是有些不妥;离职的两个月之后 里,我当时为了体面,加上了「我对公司并没有什么怨念」这句话。如今读来,却觉得有些虚伪。

于是,好不容易表达出来的东西,又再次经过了一次「自我审查」。很多文章当时的情绪已经非常强烈,我确实是在克制,只泄露出一部分。以至于我很难回想起当时的我完整的想法了——既然回想不起来,那我为什么能确定我只泄露了一部分呢?因为我在写这篇文章的时候仍然时不时考虑:这里应不应该继续往下写,这里写出来合不合适。

现在,我想换一种顺序:先写给自己,写完再决定给别人看多少。这个「暂停键」大概还会存在一段时间,但至少,我不会在还没说完的时候就按下它了。


还记得建站时的第一篇文章 Hello World,十九岁的我庆祝的,是终于不必再替别人的平台创造价值。我也的确在这块属于自己的土地上耕耘了很久。只是如今的我,每个月向好几家 AI 公司交订阅费,也开始享受租来的地上的收成。

我的处境依然不明朗,但我不想再等到一切都想清楚,才开始表达。

十九岁开始开垦的「博客」这块地,至今没有租给任何人,也没有任何人能替我耕耘。这篇文章,就是荒了很久之后的第一茬收成。

云南之行:失望与惊喜

2026-04-28 10:04:27

cover

上一次全家一起旅行已经是十几年前的事情了,那时候我应该还是在上初中,某一年春节期间我们一起去的海南找我爸的朋友玩,时间过于久远,基本上只记得坐了一天多火车到湛江,火车上还是挺难受的,在路上就已经消磨大部分对旅行的热情。加上住在别人家里,导致对那次旅行留下的都是一些不好的回忆。

这趟旅行原本只是想带着父母去一趟他们想去了很久的云南,目的地没有过多考虑,反而是出行方式——我爸妈原定想跟团,因为他们不怎么会制定游玩计划,之前的旅行基本上都是跟着单位团建之类的,但既然这次我也去,自然就不会选择跟团游了。走完本次行程之后,真正让我印象深刻的,并不只是风景,而是父母在面对一次自由行时表现出来的新鲜、紧张与不适应。

本次云南之行的照片整理在这里:云南照片作品集

苍山

来大理的第一站是苍山,苍山从南到北一共有 3 条索道,分别是:感通索道,洗马潭索道(上、下段),中和索道,其中只有洗马潭索道上段的终点抵达海拔接近 4000M 的洗马潭,洗马潭上下两段在七龙女池中转,并与感通索道、中和索道通过玉带云游路相连。

我们因为担心刚来高海拔地区并不适应,加上网上看到说最近洗马潭属于枯水期,于是就不打算乘坐洗马潭索道上段了。我们是从中和索道上山,然后沿着玉带云游路一直走到了感通索道下山。一共大概花了 6 个小时,这个玉带路挺好的一点是平路,基本上没有太大的爬升和下降,不过平均海拔也有接近 2600M,我在说话比较快的时候还是能感受到一些喘不上气,不过我父母倒没有这种现象。

苍山中间的这段玉带云游路景色其实挺一般的,洗马潭山顶或许会好一些,我们游览的这天因为天气不是特别好,大部分时间都是被云层覆盖,在山上向洱海看去,一片灰蒙蒙的感觉。直到我们从感通索道下山的时候,天气才稍微晴朗了一些,能够很清晰看到山下的城镇以及远处的洱海。

如果时间比较充裕,苍山可以分为 2 天游览(不过很可惜苍山的门票是当日有效),因为苍山本身可游玩的点其实不少,除了玉带路全线,还有从感通入口步行上山的感通寺、寂照庵等。不过我个人感觉没必要,虽然可游览的地方多,但没有好看到值得花费 2 天在这上面的地步。

三塔、古城

第二站是崇圣寺三塔和大理古城,这两个距离非常接近,所以安排在同一天游玩。

崇圣寺针对 3 天内落地大理机场的人,是可以免门票游览的(电瓶车不免)。不过崇圣寺除了三塔外,其他都是 2004 年开始重建的。这也导致除了最深处的大雄宝殿、观音殿、罗汉殿,其他区域已经很大程度上变成了售卖文创产品、下午茶的‘商业店铺’。

我们是购买了单程的电瓶车票,从入口送到大雄宝殿,然后再一路走下来,时间比较充裕的话,也可以慢慢走上去,景区还是挺大的,游客也很多,还遇到了很多外国人。午餐在寺庙内吃了素斋,味道还不错。

从三塔出来,沿路走一公里多一点就到了大理古城的北门,之前一直听说大理古城商业化很严重,来之前并不理解商业化到底是什么意思。来之后才明白,古城里面满是商铺以及民宿,大部分都是咖啡、鲜花饼、奶酥等网红店铺,售卖的东西又贵又重复。管理也很混乱,汽车、电动车穿行在游客之中,如果不是特别喜欢古镇,不建议专门来。

环洱海

第三站是洱海环线。我们从古城附近出发,原以为一天就能环完,但其实是不够的。虽然洱海一圈只有 130 公里,但开一圈至少要 4 个小时。而且如果是顺时针走,到晚高峰必会在南边堵车,所以如果一定要一日内环洱海,建议逆时针走,上午先走海东,沿路开过去,理想邦、双廊等几个小镇也没有逛的必要,但天气好的话,这条海边公路看着还是不错的。然后一路开到蝴蝶泉或者西湖,蝴蝶泉和崇圣寺一样有 3 日免门票的规定,然后午饭可以在喜洲古镇里吃。

我们当时的体验就比较差劲了,因为当天天气很不好,一直是多云,风也大,洱海真的是非常吃天气,如果天气不好,水也是灰色的。而且当时包车的司机服务态度也挺一般的,我们上车就说要环洱海游,司机就一直说海东没什么玩的,就让我们一直在海西这边玩,但问题是那天天气很不好,海西也挺一般的,司机还在不断表露出作为本地白族人的优越感,带着父母出门在外,我也懒得和他争了。

我更推荐的游览线路不是包车,而是租一辆自行车或者电动车,午后沿着洱海生态长廊骑一段距离,应该是挺舒服的。不过我爸不会骑车,所以我们没有这么做。

洱海周围的几个景点没有必要去,包括但不限于:龙龛码头、S 湾、喜洲古镇、双廊古镇、小普陀、理想邦。这几个景点,如果天气不好,效果很一般;但如果天气好,随便一处海边都很漂亮,更加没有必要去这几个景点了。

大理总结

如今回看大理的游玩体验,我只能给到 5 分(10 分制),苍山甚至是体验最好的一天,随后两天一天比一天差。我认为大理更适合的游览方式是长期度假、住海边、慢慢玩,而不是作为一个被带上过高预期去打卡的旅游城市。大理一半是城市一半是景区,但是景区的管理又明显跟不上:比如喜洲古镇,虽然本身不要门票,但是接驳车要收费,麦田小火车要收费,严家大院要收费,甚至还有本地居民也会开电瓶车在景区里揽客。我并不是反对商业化——只是我在大理看到的是它缺乏体面的商业化:各种分段式收费,只想变着花样去收割游客。

我对大理的不满并不是说具体的某一点不好,而是整个旅游体验太像被营销吹上天之后的半成品:天气晴朗的时候,洱海的好风景自然也有;古城当然也热闹,但也只剩下热闹;景区也能逛,但都是想着怎么收割游客;城市规划也很差劲,本地人的生活区和景区交错,但二者都未形成舒服的游览秩序。

丽江古城

本来在大理的时候,因为逛了 3 个古城,体验都挺不好的,直接导致我对丽江古城也产生了一种抗拒感。

所以就只安排了半个下午的时间去逛逛,但是不得不说,人生有时候就是这样,你越期待一件事情,结果往往越不尽如人意;你对一件事情越不抱希望,它反而越可能给你一些意想不到的惊喜,丽江古城就是如此。

丽江古城是禁止车辆驶入的,地面也比大理古城宽敞、干净很多,整体的建筑风格也比较偏向于大众认知的“古镇”:沿路的石凳,两边的店铺都悬挂着灯笼,所以整体的闲逛、游玩体验比大理强不止一筹。从南门进入,一路往北走,大部分景点、寺庙、纪念馆都是免费的,游览这天的天气也很棒,从文昌宫俯瞰整个丽江古城,心里只剩下两个想法:1. 真漂亮啊;2. 大理的古城都是什么垃圾玩意。

随后逛到北门大水车,然后继续沿着街道向忠义市场闲逛。晚餐在忠义市场的一家街边小摊吃的,味道也很不错。

玉龙雪山

本来我的丽江行程里并没有安排玉龙雪山,因为看到网上说的玉龙雪山海拔有四千多,我担心我们生活在平原地区的人过去会有高原反应,但之后才了解到玉龙雪山和苍山一样,是有 3 条索道的,只有冰川公园的索道会上到 4500 米左右,而云杉坪和牦牛坪的索道海拔只有三千多米。尤其是云杉坪,海拔只比山下高了不到 300 米,加上在大理的这几天对古城的印象实在不好,也不想在丽江继续花时间在更多古城上了,所以就在去丽江的前一天才正式订的玉龙雪山票,冰川公园的大索道票自然是没有了,牦牛坪的索道检修中,只剩下云杉坪的票了。

还是那句话,对于一件事情越不抱希望,反而会给一些意想不到的惊喜,网上铺天盖地的都是说冰川公园的索道票很难抢,本地的出租车司机也是建议去大索道,云杉坪都没什么人讨论,但真正抵达时,云杉坪还是给了我相当大的震撼:云杉坪的开阔,加上近距离仰望雪山的压迫,心里只剩下了感慨——还好来了玉龙雪山,也算是不虚此行了。

云杉坪下来之后就逛了蓝月谷,下来之后天气又开始在多云和晴之间转换,也导致湖水在蓝绿之间不断切换。不过下午的蓝月谷有个问题,朝着雪山方向拍摄时基本都是逆光。所以或许可以考虑先游玩蓝月谷,再去云杉坪。

黑龙潭

因为是下午的飞机离开丽江,所以上午还剩下几个小时,就去了在古城区的黑龙潭。黑龙潭门口停着挺多旅游大巴的,里面不大,因为很大一部分面积是象山,但是登山入口被拦住了,不让进。景观基本上就是围绕着几个水潭,雪山倒影还是挺漂亮的,另外这里清晨也是可以看到日照金山的,我们离去的当天天气非常好,可以说万里无云,不过可惜没有起得太早,没看到日照金山。

黑龙潭本身是 4A 景区,除了水潭边,还有东巴文化研究院介绍纳西族的风俗文化等,算是一个小博物馆。景区都是免费参观,离市区也近,花 2 小时逛一下还是挺值得的。

丽江总结

丽江的行程充满了惊喜,我可以给到 8.5 分,虽然时间呆的比较短,但是去的几个景点没有踩雷的地方,甚至可以说充满了惊喜,并且大理景区的一些毛病在丽江也有很大程度的改善。当然缺点也有,比如玉龙雪山的景区范围大得吓人,只要进入这个范围,就需要 100 元的进山费,实际上的收费处距离游客中心还有接近十公里。只是相比大理的景点来说,玉龙雪山至少在景观回报上撑住了这个价格,而不是让我觉得被收割。

我认为丽江是一个更值得我花时间的地方,无论是人文还是自然景观。也让我意识到,我不是不喜欢古城,也不是不能接受商业化,而是不能接受一种粗糙、混乱、只知道收割游客的古城。

餐饮

在大理吃的其实挺一般的,因为都是在大众点评上找的,但是我感觉很多店铺都是刷的,所以不用太在意大众点评的评价就好。就在饭点附近在本地人居住的地方随便找一家白族特色炒菜吃就行了,其他的汽锅鱼、石板烧其实并不特别推荐,云南的蔬菜因为日照充足、海拔高、昼夜温差大,整体都挺好吃。

有了大理的经验,在丽江吃得就不错了,不管是忠义市场的家常小炒,还是炸菌子、炸土豆等小吃,价格都不贵,味道也不错。大理、丽江这里的饮食都偏重口,江浙或者广东地区的人可能吃不惯。

感想

本次旅行也算是平稳结束,父母在旅途中偶尔流露出的新鲜和紧张,让我有些感慨,对我们来说再普通不过的大众点评、携程、导航,对他们来说其实是一条新的学习路径。也难怪很多老年人出门更愿意跟团——也许并不是他们喜欢,而是暂时被科技时代甩在后面的人,已经没有其他的选择了。

我对 DIY 市场、AI 的一点看法

2026-03-04 11:58:13

cover

我前几年使用电脑主机的强度并不高,因为我开发一般都是习惯用 Mac,用这电脑主机多是以打游戏为主,而我玩的 3A 游戏更吃的是显卡,虽然竞技类的网游也玩,但不会追求特别高的帧率,基本也就是锁定在显示器的刷新上限,也导致我基本上一直没有碰到什么 CPU 相关的瓶颈。

直到过去这一年,我开始尝试将日常使用的重心转移到了 Windows 上,让我愈发感觉到了这台主机的吃力,所以去年我又升级了 32G 的内存条(划重点!)。虽然多任务切换的卡顿有了一些改善,但是编译时间以及打游戏的 1% LOW 帧仍然没有改善。加上最近遇到了几次正常使用着突然黑屏重启的情况,仔细排查了许久发现显卡延长线出问题的概率最大,毕竟它也是买机箱附赠的,也用了五年半了,还是一根 PCIe 3.0 的线。我纠结了许久要不要干脆换掉这个机箱,有些舍不得这个全铝机箱的质感,又回想起 ITX 装机的痛苦回忆,权衡之下还是下定决心把这套电脑主机给换掉了。

更新换代

于是乎,我就开始研究平台了,这次我本来想换到 AMD 的平台,试试看 X3D 的大缓存是不是打游戏真的有那么强。不过在我查看了一下 DDR5 的内存价格之后,我放弃了这条路——倒不是说买不起,只是我一般的原则是:可以买贵的,但是不能买得贵。目前 DDR5 这个内存价格(32G 就需要 3000 元以上),我反正不会去支付这么高的溢价。大不了继续用着去年买的 DDR4 32G 内存了。

升级配置但是保留内存平台不变,这也意味着电脑主机后续升级的路已经到了尽头。这代表着 3 - 5 年之后,如果出现 CPU、内存条、主板等任何一个部件拖后腿的情况,就只能全部换掉。这种方案或许并不适合所有人,不过我倒是没有纠结多久就下了这个决定。

决定继续保持 DDR4 之后,选择反而更清晰了,不用再纠结 AMD 了,因为 AMD 最后一代支持 DDR4 的是 5 系,而 5800X3D 游戏性能虽然不错,但是多核能力在如今实在是捉襟见肘。于是转而看向 Intel 阵营,只剩下 Intel 的 14 代可选了,对比之下,我选择了 i5 14600K 盒装 + 技嘉 B760M Aorus Elite,机箱我选择乔思伯 Z20 机箱,mATX,20L 容量。不过坦白说,这机箱的钢板质感相比之前的全铝质感机箱不知道差到哪里去了。

装好机器后,看着这套依然只能沿用 DDR4 的新主机,我一直在思考,为什么内存的价格会涨得这么离谱?深入挖掘之后,我发现,看似小众的 DIY 市场,其实每个消费者都在为这场 AI 的浪潮买单。

AI 的浪潮

人们总说是因为 AI 的发展,导致内存的需求扩张,进而导致供不应求的情况。其实并不是这样,AI 需要的是显卡算力以及显存。而显存的颗粒和内存的颗粒其实都是由镁光、海力士、三星为首的存储厂商提供的。

尤其是目前英伟达的 H100/H200 显卡要求的显存颗粒是 HBM,而不是普通游戏卡的 GDDR6 / GDDR6X。而 HBM 所消耗的晶圆数量是同样面积的 GDDR / DDR5 的好几倍以上,良品率也低。

互联网头部大厂算力需求又非常夸张,加上存储大周期的减产,各种因素叠加直接导致存储厂商的产能跟不上了,不得已去调整产能结构 / 资源配比去满足 HBM 的需求1。导致内存的供给出现了非常严重的匮乏,也让价格一飞冲天,我去年 5 月份 300 买的 32G 内存,到现在已经涨了接近 6 倍。

存储厂商也不傻,HBM 做出来就有订单抢着要,而且相比 DDR 利润又高。只能把 DRAM 的产量减少了。所以在我看来,消费级内存涨价的根本原因其实不是内存的需求扩大了,而是产能减少了。

想想 DIY 玩家也是挺可怜,前几年被老黄割韭菜,最近一年又被存储厂商割韭菜。

资本内循环

这是当前 AI 浪潮中最最危险的地方,很多投资者已经意识到了不对,举例:

  1. 注资:巨头们(Microsoft2,Google,Nvidia,Amazon3)向 AI 初创公司们(如 OpenAI,Anthropic)投入几十亿甚至上百亿美元;

  2. 回流:初创公司们拿到这笔钱,因为需要训练模型,便立刻向巨头们签下合同购买云服务(Azure / GCP / AWS)或者芯片(Nvidia);

  3. 财报:巨头的财报上,云业务和芯片业务营收爆炸式增长。

股价也伴随着营收增长而飙升,但钱并不来自于外部,而是来自于圈子内部,在账户之间转了一圈,就凭空创造了几千亿的纸面财富。

普通消费者在这个产业中,其实参与度很低,一个健康的产业逻辑应该是:巨头投入算力 -> 产出应用 -> 卖给各种消费者(外部资金流入) -> 赚到钱之后再买算力。

可现在正是消费者的资金流入这一环是缺乏的。

巨头们疯狂地卷算力,直接导致的结果就是现在算力反而越来越便宜,API 价格越来越低,甚至 OpenAI 近期针对 Free 账号都开启了 Codex 的权限。

算力的未来

目前大厂的拼命卷算力的行为4,我并不太看好。他们目前投入的钱,在我看来其实就像是一种军备竞赛,有没有用——现在不知道,但是万一 AGI 真的出现了,那不就肯定能赚回来了(?),而且大家都在卷算力,那我也要卷,我多买一点56,竞争对手就少买一点。

我个人来看,目前的算力规模其实已经基本上到了一个物理上的硬顶程度。这个硬顶,是包含两个层面:显卡本身的算力,以及配套的电力、散热等基础设施7。

从旗舰显卡的算力来说:计算芯片的工艺已经很难短期再上进了8,近两年业内一直在尝试其他的解决方案,比如台积电的先进封装工艺:将计算芯片与显存进行物理连接,这种封装技术比芯片或者显存本身的产能更能决定显卡的供给9。也因为当前这种封装技术,导致目前旗舰显卡的热量已经达到一个非常恐怖的地步,工业界同样在寻求更高的热导率材料,如果这些方面没有进步,可能显卡的频率再也无法提升更多。

未来的模型进化,可能大概率并不是堆算力,去拼谁能到物理极限性能,而是软件层面的优化。比如不再去堆模型的参数数量,而是用更优质的模型、算法,这些层面或许也会导致硬件本身的需求衰竭。

在未来,就算 AGI 真的诞生了,但是前提是它需要 100 张顶级的显卡才能训练起来,那它对于我们来说、对于通用市场来说,其实没有任何意义。资本如今卷算力的核心原因,不正是因为在赌未来能减少劳动成本吗?

我也认为,在 AGI 真正降临之前,一定会有一个过程,在这个渐进的过程中,可能 AI 本身已经能做到自我优化算法了,届时,硬件市场会有一场前所未有的崩盘。

我的看法

作为开发者,我当然期待着 AI 的快速发展,因为它也的确能带给我更优的体验;可另一方面,我又有些悲观地认为目前的 AI 距离前几次工业革命很显然还有不小的差距,也就是仅凭目前的翻译、写代码、写文档、画图产生的营收,本质上只是在蚕食已存在的岗位,并没有创造出增量市场,也仅凭当前的这些用处,显然并不足以覆盖当前的各大公司的资本支出。

而作为 DIY 爱好者,我自然希望硬件的价格越低越好、希望算力市场大崩盘,人人都能用上便宜的 RTX 5090,DDR5 64G 内存——希望如此,让子弹再飞一会。

Footnotes

  1. DDR5 合约价与 2026 年供给趋紧的判断:Tight DRAM Supply to Boost DDR5 Contract Prices—Profitability in 2026 Expected to Surpass HBM3e, Says TrendForce ↩

  2. Microsoft 与 OpenAI 的联合声明:Microsoft and OpenAI joint statement on continuing partnership - The Official Microsoft Blog ↩

  3. Anthropic 接近完成 35 亿美元融资,Amazon 作为重要背书股东:Anthropic closes in on $3.5 billion funding round as investor interest soars ↩

  4. 预计 2026 年 8 大 CSP 的 CapEx 将超过 6000 亿美元:CSP CapEx Expected to Exceed US$600 Billion in 2026, Ushering in a New Growth Cycle for the AI Hardware Ecosystem, Says TrendForce ↩

  5. Amazon 预计 2026 年 CapEx 约 2000 亿美元:Amazon sees 50% boost to capital spending this year, shares tumble ↩

  6. Alphabet 预计 2026 年 CapEx 可能大幅上调:Alphabet says capital spending in 2026 could double, cloud business booms ↩

  7. Uptime Institute:数据中心用电规划创纪录 ↩

  8. MoS₂ 等二维半导体在实验室层面替代硅的可能性:Gate structuring on n-type bilayer MoS2 field-effect transistors for ultrahigh current density | Nature Materials ↩

  9. 台积电的封装被订满,计划 2026 扩产:[News] TSMC’s CoWoS-L/S Reportedly Fully Booked, OSAT Partners Step up with ASE’s CoWoP in Focus ↩

重构我的博客

2026-01-11 21:19:48

cover

时隔两年多,我终于再次对博客下手了,之前的每次都是折腾博客内容样式、构建流程,本次我将重点放在了架构的整理上。得益于如今 Vibe Coding 的成熟,本次重构虽然工作量是「历史之最」,但对于我个人来说,却是我最享受的一次:结构化的梳理、复杂度的降低,以及部署的自动化。

各模块介绍

目前博客涉及到的所有服务大致可以分成 5 个模块,其中部分是在自己的 VPS 上托管,另外部分在其他的 SaaS 服务商托管。

内容

博客的内容仍然保持纯 Markdown 形式,因此构建输出的的也是纯静态文件,可以很方便托管在 Cloudflare Pages,不需要 Worker 或者 KV。

之前一直用的 Hugo + SolidStart 方案,Hugo 负责内容将 Markdown 渲染成 HTML,SolidStart 再提供页面的组件样式,这套流程很别扭——或者说我的实现很别扭:SolidStart 是 file-based 的路由,所以我在 src 目录做了一个软连接指向了 Hugo 生成的目录(都是 JSON 格式的文件),然后SolidStart 这边动态解析 JSON 文件然后还要对已经渲染成 HTML 的重新解析,对某些已渲染的内容做一些替换,比如:高亮/数学公式渲染等。而且这部分只能放在构建的流程做,所以我又写了几个 Vite 插件。

但是由于我博客的分类、RSS、站点地图等都是 Hugo 做的,用 SolidStart 来重写倒不是做不到,就是有些麻烦。加上我好不容易打通了这一整套流程,所以就一直保持着现状了。

评论

从建站后很长一段时间,我使用的是 Disqus,评论数很少,而且 Disqus 广告又多,加载又慢,我嫌弃太臃肿,原本的评论我也没删,导出之后会自动在博客评论区以只读形式展示。

2023 年 8 月,我将 Disqus 换成了 giscus,一款基于 GitHub Disscussion 的评论系统。两年时间用着倒是还行,但是前段时间 Next.js/RSC 爆发了非常严重的安全漏洞,我在排查的时候,发现了 giscus 也是基于 Next.js 开发的。好消息:giscus 使用的 Next.js 版本不在漏洞影响范围内;坏消息:12.x 版本早已被官方停止维护了。

giscus 或者是 utterances 都是基于 Github OAuth 认证的 + 在页面通过 iframe 嵌入,考虑用户在点击授权时,凭证都是存储在第三方应用服务器的,在我看来,始终还是有些不可控的隐患存在。

搜索

搜索模块是两年前才加上的:Tantivy(Rust 编写)作为搜索引擎,Golang 作为 API 服务通过 RPC 去调用,我当时还专门自学了 TLV 编码 + TCP 连接池保持二者的通信。之所以这么做,是因为当时我对 Rust 实在不熟悉,当时又有部分 API 是用 Golang 写的并且正常运行中,所以就正好合进来了。

这个模块确实是我有炫技的成分,把一个功能非常单一的组件和另一个基本上无关的组件捆绑了,初期调试一度非常困难:必须要同时启动两个服务,同时连接池的释放问题也出现过 bug。

点赞 + 豆瓣秀

这两部分是用 Elixir Phoenix + PostgreSQL 数据库。数据库就是使用的的 AivenCloud 的免费版方案,后端服务则是托管在 Gigalixir。

点赞组件也差不多上线运行了两年,之前一直没有介绍过,正好介绍下。点赞本身只能点一次,数据持久层是放在 PostgreSQL,同时热数据存在内存里(更准确地说是 ETS 表中),所有操作一律只针对内存,定期同步至数据库。

豆瓣秀则是一个爬虫,每天运行一次爬取个人收藏页面,入库,页面只请求今年以来的数据。

请求同样经由 API 网关转发给 Gigalixir 的服务。因为数据量小,Gigalixir 的免费版倒也够用,唯一的问题就是,免费版要求 30 天内必须提交一次更新/部署,不然就会被托管方停掉服务。

站点统计

这个模块是我目前博客最重的服务,用的是自部署的 Plausible 方案。它提供的功能还行,但是搭配的后端数据库太复杂了,同时使用了 PostgreSQL + Clickhouse,全套服务都是在我的服务器上运行。

Clickhouse 是典型的内存大户,应对大流量的 OLAP 很好用,但问题是我的博客每天就一百人访问,属实是用不上 Clickhouse。很可惜的是,Plausible 本身不提供只用 PostgreSQL 作为唯一数据库的轻量部署方案。

复杂度是一种债务

运行维护以上的各种服务,很显然并不轻松。

语言栈的分裂

博客内容的生成我就用了两种语言:Hugo 的模板语言 + JavaScript(Solidstart) ,后端就更多了+ Rust(tantivy)+ Go(API 服务)+ Elixir(Phoenix) + 两套 DB(PG + ClickHouse)。

对个人开发者来说,在开发时选择体验不同语言的新鲜与舒适感是一种隐形的超前消费,在运维时终究要加倍偿还。

部署位置的分裂

目前博客的前端部署在 Cloudflare Pages,后端却同时部署在好几个不同的地方:自建服务器(搜索/统计/SSR)+ Gigalixir(Phoenix)+ Aiven(数据库)。

尤其是搜索和点赞,这俩模块的链路是尤其长,之前排查过几次也是相当费劲。

Plausible 的重

这一点问题其实和前两点不一样,Plausible 本身用的是 docker compose 部署。唯一的问题是两套数据库(尤其是 ClickHouse)在运行层面带来的:占用运行内存大、占用磁盘空间也大,升级的风险也大。


与 ChatGPT、Gemini 反复进行了数次讨论,围绕着更工程化、好维护的目标,最终敲定了一套最适合我的重构方案。

前端重构

把博客当前的功能以及我的要求发送给了 Gemini,然后让它出具了几个不同的页面。不得不说,Gemini 3.0 在写前端样式真的比 ChatGPT 5.2 强太多。目前前端的内容构建流程已经去掉了 Hugo,所需功能全部由插件或者手写代替了。

设计风格

重新设计了更加统一的配色方案,只保留一个强调色(#1f6f6a)的同时,尽可能减少其他除了黑白之外颜色的出现。

重新设计了各组件(主要是链接)的交互方式:

  1. 顶部导航栏以及工具栏:仅 Hover 时切换到强调色;
  2. 首页的「继续阅读」、「查看更多文章」等跳转页面,加上了指引箭头,hover 时变强调色;
  3. 首页的文章标题,hover 仅加下划线,这里的标题字体比较大,如果 hover 时候变强调色,会显得很突兀;
  4. 底部页脚部分,严禁出现强调色,而是通过更浅一级的字体,hover 时候加深来体现可点击。

代码高亮

从 highlight.js 切换成了 shiki 方案,也是在构建期完成,shiki 的速度比 highlight.js 慢很多,但是精细度更佳。

为了确保与整体设计风格一致,没有采用现有的配色方案,而是让 shiki 只做语义化 Token 的标注:函数、常量、关键字、注释、操作符等等。配色统一使用 CSS 变量定义。

图片相关

  1. 去掉了所有非必要的图片:头像,以及文章封面图。提升加载速度的同时,也让我不用在写完文章之后纠结到底用什么配图了;
  2. 原先的 og:image 使用的是文章的插图,现在都改用了在构建期使用页面元数据绘制生成,会更像文章的封面;
  3. 重新设计了站点 favicon,换成了更具有个人品牌特色的图案。

评论

去掉了 Giscus 组件,现 GitHub Discussion和旧时的评论会由后端统一返回,前端统一渲染。对于缺少头像的评论(比如 Disqus),头像缺省使用名字的首字符。

其他

  • 文章排版统一交给了 UnoCSS 的 Typography preset 方案。仅微调了字号和颜色;
  • 文章侧栏的社交区块放在文章尾部,优先确保阅读体验;
  • 还有很多小细节,就不一一列举了。

后端重构

后端方面主要就是和 ChatGPT 进行讨论了,仍然是先梳理出各模块的功能,合理化组织架构,再交由 Codex 实现。目前后端的服务全部使用 Rust 实现,分为两部分:API 和 Jobs(定期同步等任务)。数据库也减少到 1 个,均在我个人服务器上部署运行。

评论

关于评论模块该如何实现我很是纠结了一阵子,也详细调查了纯自建、纯托管等方案的优劣势,权衡之后,决定采用折中的方案——评论源还是采用 GitHub Disscussion,页面只做展示。由后端定时查询 GitHub Disscussion 存入数据库,文章页面底部的评论区只展示评论内容,不展示评论框,需跳转到 Github 参与评论。

我也在设计「点击跳转才能回复」时纠结了许久,认为这个额外的点击跳转步骤可能会对用户有些许不便。但最终还是采用了这个方案:可以显著减少组件实现的复杂度,也不需要用户点击授权才能回复,安全性也有保障;再就是,对于首次评论的用户,其实和之前 giscus 时回复的流程一样,无非是把跳转授权改成了跳转到 GitHub Disscussion 对应主题。

搜索

搜索的功能大体上没有做改动,还是用的 Tantivy 方案,只是目前不再需要跨进程 RPC 调用了。

针对新文章的更新做了优化:博客构建完成时,会触发 Webhook 到后端,然后后端直接获索引最新文章;以防 Webhook 发送失败,也做了定时更新的兜底机制。

点赞 + 豆瓣秀

这部分逻辑比较很简单,直接重写成 Rust 版本了。

站点统计

不再使用 Plausible,改成自建统计方案,分为 2 个接口:

  1. /pv,首次进入页面即发送信号;
  2. /engage,页面变动:关闭、跳转前,通过 navigator.sendBeacon 发送浏览时长数据。

做了一个简单的后台页面,只含:页面浏览量、浏览人数、时长;路径、设备、来源、国家等指标。

部署

也重新整理了一下部署相关的流程,目前全部使用 Podman Quadlet 方案完成自动化部署。这个方案实在是太方便了,我所有的服务现在都由 Quadlet 来统一管理部署:

  1. 设置代码仓库本身的 CI,比如:指定分支提交会触发 Github Action 的构建,推送镜像到 ghcr;
  2. 设置服务器端的 .container 配置文件,指定镜像为 ghcr 镜像,同时开启 AutoUpdate=registry;

这样,后续的功能修改就不需要手动管理了:

  1. 代码修改之后,推送到 Github,会触发 Github Actions 的构建,推送镜像到 ghcr.io;
  2. podman-auto-update 会定期(通常是每天半夜)检测所有通过 Quadlet 创建的容器是否有新镜像,并重启服务;

重启服务、查看日志等用的都是 systemd 的那套命令,真的极大减少了心智负担。

写给 28 岁的自己

2025-09-10 21:43:27

cover

临近我 28 岁生日时,我原本并没有写文章的打算。但这几天,一股强烈的倾诉欲突然涌现。一方面,近期似有若无的迷茫始终萦绕,我不知如何去捕捉并驱散这种迷茫,只能试着用文字描摹出我当下的心理状态;另一方面,也是最关键的,我想通过这篇文章,对照着过去几年写给自己的文字,看看我是否活成了曾经期待的模样。

恋情结束

今年我的状态并不好,很大部分原因是突如其来的分手,前女友在很短期的时间内喜欢上了她公司的其他人,向我并提出了分手。一开始出于恐惧失去这份感情、这份生活方式,我不断尝试过沟通,找出我们之间不契合的点,甚至努力改变自己以挽留她。但没有什么结果,四月中旬彻底分手。

分手后我们仍有一些事情纠缠在一起:我的 Spotify、VPN、ChatGPT 订阅都还在和她共享;我之前在深圳的一些行李物品也都还在她家里放着,毕竟我家里在装修,所以就想干脆等家里装修结束之后再寄回来。前几天,我告知她可以把我的东西寄回给我了,她说我的显示器用着还可以,想继续留着用,我想了想家里的显示器也够,而且也不知道外包装还在不在、能不能邮寄,就答应了。

东西寄完之后,我觉得是时候为这一切划上句点了,便告知她若想继续使用订阅,需从今天起和我平摊费用。她立刻回道:「那快递费也要你自己出哦」。看到这句话的这一刻,先前所有的不甘与残留的温情仿佛瞬间蒸发。我的指尖在键盘不断敲击,又反复按下退格键,最终语气平静地回复:「可以,那也请你结清这几个月以来的订阅费用以及显示器的折旧费吧」。她争辩了几句,我脱口而出「你不懂感恩」。她沉默后道歉了。而我在那一瞬间感到的并非是胜利,而是一阵深刻的恶心,随即是前所未有的清醒——或许我不想承认,但这几个月我一直在用「共享订阅」等方式拖延告别。我的内心或许还期待着一丝感激,而对方却早已将这一切视为理所应当。

我忽然明白:若要靠自己不断让步才能去挽回这段感情,就算能挽回,而自己也必然会失去下一次的自己。莫名地又觉得她这次的道歉有些讽刺,恋爱的时候道歉总是我先说出口。

这一段自 2020 年 3 月起,长达五年的感情,以这样的形式收尾了。我也终于完成了对这段关系的祛魅。这五年我也经历了很多难忘的时刻,我坦然为我当时的心动买单,我并不后悔,换成下次我依旧敢这样。

分手后带来的情绪波动,也让我更容易的陷入了对未来的迷茫之中。

迷茫之中

迷茫并不是在最近才纠缠上我的,或许它始终围绕在我的身边,前几个月还有装修分散我的精力,但如今尘埃落定,这几天的迷茫情绪又开始占据上风。细想之下,这份迷茫,底色是我对未来的不确定。

每当我站在人生的十字路口时,前方总会出现一团迷雾,让我无法看清前方的路,也不知道该朝哪个方向走。在大学的时候,我就想我以后一定要找一个离家很近、工资也不低的工作;第一份在武汉的工作满足了我对未来的期许,可惜遇到了管理风格我不能接受的领导,此时我又想我一定要找一个轻松一点,让我自己能学到东西的工作;在下一份深圳的工作我又满足了上一次对未来期许,但好景不长,让我对接客户时,我又想我一定要找一个更轻松的外企,不再有对接客户的烦恼;直到离开上家公司,现在我却没有找到一个轻松的外企了。

如今回首看这几个关键的十字路口,不论我当时下定多大决心、做的什么决定、在不久后我发现我都选对了,只是在此刻以结果论来看也没有多么大的区别。虽然我的工作生涯暂时停止,但人生永远都会有新的十字路口出现。时间总会向前推进,和我处于什么状态都无关。

我也明白了一个道理:当你有工作的时候,几乎所有的烦恼都是和工作相关的,心里想的都是放假、辞职、休整。可当你真的没工作了,会发现要面对的烦恼更加复杂、多样化。因为工作本身不止提供给你工资,还会给你带来社会身份与地位的认同感,当在职时的焦虑从时间稀缺、工作内容厌恶转变成了离开工作岗位后对金钱与前途的不确定,很难说二者谁更耗费心力。根据我的经历来看,这二者之间心态的转变通常会在半年左右稳定下来。

我有些朋友在离职之后,会非常的焦虑,我也会劝他们在家好好休养一段时间,但他们担心长时间休养会让自己「退化」,这样会不会无法再融入到职场之中,陷入一种对自我存在性的焦虑,所以往往就是一段工作紧接着下一段的工作。我并不属于这样的人,两年多过去了,在刚离开工作岗位前半年会想想当时是不是继续工作是更好的选择,半年后这种想法已逐渐消散,如今我偶尔也会怀念一下公司上班时的日子,但我确信我已经无法再回到这种日子了。

对于如今又站在人生十字路口的我来说,执着一定要先找到驱散眼前的这片迷雾的办法,或许并不是最好的办法,只需要慢慢沿着过来的道路前进,终究会能看清脚下的路。

最近也和一个很好的朋友聊我的困惑,他说:「人的组成不光是靠精神或者意识,同时也靠肉体」。迷茫是属于精神层面的,这方面目前的我或许把握不住,但没关系,试着慢慢学会在精神层面与迷茫共处的同时,把握住肉体层面我能掌控的就好(比如健身)。

8 年前的期待

随着年纪增长,越发感觉到时间的残酷,刚毕业那会,我十分确信我能凭借技术找到一份不错的工作,因为对当时的我来说,技术就是我的兴趣爱好,也是我所追求的。但从 2021 年起,GitHub 的提交次数逐年下降或许在暗示我对「技术本身」的热情正在逐渐减退,这也同样加剧了我的迷茫与焦虑。

但我不知如何才能去干预这种心态的变化,亦或者我不知是否应该去干预。这并非是我技术水平下降的多么厉害——如今 AI 技术的发展迅猛,善于使用工具的人只会比过去的人技术更强。让我不安的是:我是不是失去了「用技术改变一切」的心气。我常听到「技术只是工具」「技术应服务于业务」。可如果连手持工具的欲望都淡了,业务于我又有什么意义?所以我之前一直提醒自己要对技术保持热情。

直到这次家里装修,我才意识到:我并不是失去了「用技术改变一切」的心气,而是走出了「手里只有一把锤子、眼里都是钉子」的阶段。心气还在,只是从「迷恋技术工具」转向到了「在现有条件下解决问题」上。

这段时间我把热情投向了生活里存在的问题:独立设计并施工小型健身房;自己配木板并改色与桌腿做升降书桌;搭建铝型材衣柜;自选五金与柜门,拼装折叠衣柜门等等。这些产品同样有用户(我和家人)、有约束(预算、动线、美观)、有迭代(按现场不断改设计稿)、有交付(可用性、可维护性)。这种成就感相比于我独立上线了一个项目来说,有过之而无不及。

回看当年我 写给 20 岁的自己,大部分文字如今看来略显稚嫩与理想化。唯独文章末尾那句:「我不要自己做到最好、最优秀,只希望能在接下来的时光里,变得柔软而坚韧」,至今读来仍令我感慨。如今 8 年过去,我可以说:我的确做到了。只是在前进的过程中,心里偶尔也会闪过念头:柔软与坚韧,就够了吗?我似乎仍在寻找一个确定的答案,却始终没有定论。但这个答案真的重要吗?

28 岁,我渐渐明白,或许我不必执着于一个答案,我只需要继续相信这一路走来的方式。愿我继续保持柔软、选择坚韧,在迷茫中走出属于自己的路。也许在未来某个瞬间,我会意识到:原来这一路走来的过程,就是答案。


阴历生日还未过去,所以这句祝福还不算迟——28 岁生日快乐,送给自己。

Solana 地址前缀字符概率分析

2025-05-10 22:11:23

cover

最近有人在我的 SolVantityCL 的项目里提了一个 Issue,说了一个很有意思的问题:某字符串在分别作为前缀和后缀时,找到满足要求的地址耗费的时间是不一样的,差距还很大。

我一开始没太把这个问题当一回事,只是简单回复了一下他,说这个是算法的问题,因为 Solana 即使私钥连续递增,但公钥的变化仍然是无序的,因此按照概率去预估耗费的时间可能会有误差。但是他又回复说他使用 Solana 的官方 Keygen 命令发现同样的字符串在前缀和后缀的难易程度的差距并没有使用我的工具表现的差距这么大。

这就有很有意思了,也引起了我的兴趣。所以我专门花了点时间研究了一下这个问题的背后原因。因为我很确认,我使用的 ED25519 密钥生成的算法是正确的,不然的话公钥也不会和 Solana 的 Cli 算出相同的结果了。正因如此,这才是我感觉到奇怪的地方。

所以我去翻了一下 Solana-Keygen 的源码,有收获,但和我预想的并不一样。我以为是它的随机数种子获取的方式的和我不一样,但查看之后我发现它用的仍然是从系统的随机数种子取的字节(rand_os::OsRng);不过我发现它还额外包括了剪枝操作。这个操作本身是在用户指定某些前缀的情况下,在匹配前缀前,就过滤掉某些非法的地址。这样能稍微省略掉一些前缀 / 后缀模式匹配的时间。但是,这仍然无法省略掉通过私钥派生出公钥的过程。

举个例子:当用户指定的前缀是 a 时,那么如果私钥生成的公钥的地址是 44 位的,那么就意味着不需要进行后面的前缀匹配操作了,因为用户指定的前缀是 a 时,生成的公钥地址一定是 43 位的——很神奇对吧?接下来本文就深入分析一下,看看究竟是什么原因影响了不同字符前缀匹配的概率。

在此之前,我想先列一下 base58 所用到的所有字符集合:123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz

公钥中隐藏的规则限制

ED25519 所使用的公钥是 32 字节的长度,那么它理论最大值就是所有字节全部都是 255 的情况:

>>> from base58 import b58encode
>>> max_bytes = (2**256-1).to_bytes(32, 'little')
>>> b58encode(max_bytes)
b'JEKNVnkbo3jma5nREBBJCDoXFVeKkD56V3xKrvRmWxFG'
>>> len(b58encode(max_bytes))
44

这个公钥坐标经过 base58 编码之后地址长度是 44 位,首字符是 J,这意味着在 44 位长度的地址里,不会出现 J 往后的字符了:K,L,...,Z。因为如果出现了 J 之后的字符,那么 44 地址的长度通过 base58 解码之后的字节数就要超过 32 了。

这也意味着,在 K-Z,a-z 的字符里,如果你想要它在地址的首字符出现,那么只能是 43 位长度的地址。

Base58 字符总长度 数值区间 占 32 字节全集合的概率
44 字符 5843≤N<225658^{43} \leq N < 2^{256} ≈ 94.20 %
43 字符 5842≤N<584358^{42} \le N < 58^{43} ≈ 5.70 %
≤ 42 字符 N<5842N < 58^{42} ≈ 0.10 %

而 43 位长度的地址空间,与 44 位的地址空间相比,占比只有 44 位的 6%。至于 J —— 理论最大值正好是 J 开头的,所以它会比 43 字符的地址多一部份的空间,但是又比 44 字符的地址少一部份空间,因为这个理论最大的地址第二位是 E,所以也不能取到 E 之后的字符空间,也就只能取 0 到 E 之间的 14 个字符,因为首字符 J 的概率是也就是其他的 44 字符空间的 14 / 58 = 24.1% 左右。

实际的测试

接下我会用代码实际模拟一下各字符的出现频率。毕竟刚刚所说的公钥理论最大值其实并不在椭圆曲线上,因此还是需要结合实际的测试结果来具体分析。

from nacl.bindings import crypto_sign_seed_keypair
import base58, secrets, collections

counter_starts = collections.Counter()
counter_seconds = collections.Counter()
counter_both    = collections.Counter()
counter_ends    = collections.Counter()

def increase_key32(private_key) -> bytes:
    current_number = int(bytes(private_key).hex(), 16)
    next_number = current_number + 1
    new_key32 = list(next_number.to_bytes(32, "big"))
    return bytes(new_key32)

private_key  = secrets.token_bytes(29) + b'\x00' * 3
for _ in range(5_000_000):
    pk, _ = crypto_sign_seed_keypair(private_key)
    addr  = base58.b58encode(pk).decode()
    counter_starts[addr[0]]  += 1
    counter_seconds[addr[1]] += 1
    counter_ends[addr[-1]]   += 1
    if addr[0] == addr[1]:
        counter_both[f'{addr[0]}{addr[1]}'] += 1
    private_key = increase_key32(private_key)

至于在 43 的地址空间里,想要判断首字符落在 K - z 的概率也要先除开落在 1 - J 的里面的情况,首字符概率大概就是 5.7% / 58 = 0.1%, 而首字符在 2 - J 的概率分两种情况:

  1. 44 地址空间里,字符 1 的概率是固定的 1 / 256,那么其他字符的平均就是0.942−125616.241\frac{0.942 - \frac{1}{256}}{16.241},分母是 16.241 是因为 J 开头的地址空间与其他的字符相比并不完整;
  2. 43 地址空间里,大概也是 5.7% / 58 = 0.1%。

因此首字符落在 K - z 区间的概率理论上相当于是 2 - J 区间里的 1.70%。

>>> print(counter_starts)
Counter({'9': 296710, 'C': 295743, ..., '2': 289724, 'J': 71823, '1': 19541, 'r': 5192,  ..., 'T': 4894})

比如我们这里选用 r 和 C 做对比:5192 / 295743 = 1.76 %,非常接近我们对于概率的计算了。

而对于 J 和 C 对比:71823 / 295743 = 24.3%,同样非常符合我们的期望。

非首字符的情况

>>> print(counter_seconds)
Counter({'3': 95358, ..., '1': 89821, ..., 'm': 83861})

对于非首字符的情况,比如第二个字符,出现的频率都是近似相同的,这也说明了 ED25519 的公钥分布还是挺均匀的。

也就是说,地址前缀的碰撞难易程度只和首字符有关——其实根本原因就是 32 字节能表达的数(22562^{256})和 44 位长度的 base58 编码能表达的数(584458^{44})不对等而已。如果这俩能表达的数正好相等的话,那么也不存在不同前缀的字符难易程度在 J 前后出现分水岭的情况了。

counter_ends 的结果我就不放出来了,大家可以自己测试一下看看,结果是和 counter_seconds 类似的,每个字符出现频率都是接近的。

字符 1 不一样吗?

你可能注意到了,首字符是 1 出现的次数其实远比 K - z 出现的次数要多,但是又远小于 2 - H。如果通过统计数据来计算频率的话 19541 / 5000000 = 0.0039082,正好是和 1 / 256 = 0.00391 的概率接近。

这也是 base58 编码里的特殊情况,base58 编码就是把字节转化成字符,而一个字节对应的是 [0, 255] 一共 256 种情况,转化成字符之后只有 58 种情况了。所以对于单字节的 base58 编码结果的首字符来看,一定是有字符是会出现多次的。但是 1 不一样,1 只有当待编码的字节是 0 的时候,首字符才会是 1,这也是 1 的概率正好是 1 / 256 的原因。

我们继续看首字符和第二个字符相等的情况:

>>> print(counter_both)
Counter({'BB': 5275, ..., '88': 4885, 'vv': 105, ..., '11': 65, 'ZZ': 65})

在首字符的统计数据里,1 是明显比 K - z 多的,但是前两位字符都是 1 的次数却突然变少了这么多。计算频率的话:65 / 5000000 = 0.000013,正好又是和 1 / (256 * 256) 接近。

因此对于前缀是 1 的情况,确实与其他的字符不一样:前缀是 1,只能意味着待编码的字节前缀为 0,而如果相同字符的前缀长度大于 2 的话,那么它就是概率最小的情况。

最终结论

假设你想匹配的前缀或者后缀长度为 LL。

对于后缀匹配来说,不同字符理论上是均匀分配的,如果你只是想进行后缀匹配,那么整个后缀命中一次的概率是:(158)L(\frac{1}{58}) ^ L。

前缀匹配则更加复杂:

区间 具体字符 区间总概率 区间内的单个字符的概率 p(C)p(C)
1 只有 1 0.39% 0.39%
2 - H 2…9 和 A…H 共 16 个 94.15% 5.88%
J 只有 J 1.45% 1.45%
K - z K…Z, a...z 共 40 个 4.0% 0.1%

整个前缀命中一次的概率需要分类讨论:

  1. 如果前缀全为字符 1,概率 P()=(1256)LP() =(\frac{1}{256}) ^{L} ;
  2. 如果前缀首字符不为 1,概率 P()=p(C)158L−1P() = p(C)\frac{1} {58} ^{L - 1};

声明:以上所有概率分析均建立在“ED25519 公钥对应的整数在 [0,2256−1][0,2^{256}-1] 上均匀分布”这一前提之上。此外,文中给出的数值均为理论概率,在实际运行中并不意味着只要尝试相应次数就一定能获得匹配结果。