第2章
第一个空洞——魔法学院------------------------------------------,边缘的暗红色光芒像余烬一样忽明忽暗。周逸凡站在它面前,能感觉到一股吸力,像站在地铁站台边缘,列车呼啸而过时带起的那股风,但方向是反的——不是往外推,而是往里拽。“你先进还是我先进?”皮克问。“你***的经验是用来问这种问题的吗?我***没进过空洞,”皮克理直气壮,“以前系统出问题都是直接回滚,谁**在线修复啊。你当这是写博客呢,随便改?”,把手机举在胸前当手电筒,一脚迈进了黑洞。,他感觉自己像是被一个巨大的筛子过了一遍。不是疼,是一种说不上来的不对劲——像是身体里所有的零件都被拆下来清洗了一遍,然后又重新装回去,但装的时候有几个螺丝拧错了位置。他低头看了看自己的手,手还在,五根手指,指甲盖下面的月牙白也还在。他松了一口气。。,高得看不到顶,穹顶上原本应该绘满壁画的位置,现在是一片灰白色的空白,像一张被擦干净的黑板。四周的墙壁上嵌着彩绘玻璃窗,但窗户上画的不是什么圣徒或天使,而是一行行发光的符文,像代码又像咒语。那些符文正在以肉眼可见的速度变淡,像墨水在纸上洇开然后消失。——不对,不全是人。有长着尖耳朵的高个子,有浑身覆盖鳞片、像蜥蜴一样直立行走的生物,还有几个飘浮在半空中、半透明的水母状东西,它们的触手末端各顶着一颗发光的小球。所有这些生物都一动不动,像雕塑一样凝固在原地。不是被冰冻的那种凝固,而是像视频暂停了,他们的衣角还保持着被风吹起的弧度,眼睛里还反射着礼堂穹顶上的光,但光已经不在了。“暂停了?”周逸凡问。“冻结了,”皮克从他肩膀上跳下来,落在地上几乎没有声音,“这个空洞所在的地址空间被隔离了,里面的所有进程都被挂起。你看到的这些——这些生物,”周逸凡接过话,“是这个世界的进程实例。精确地说,是[**gic_overflow]僵尸线程派生出来的子进程。那个线程存在了三百多年,派生了几千个子进程,这些子进程分布在世界的各个角落,构成了你们所说的‘魔法体系’。现在父线程死了,子进程全部变成了孤儿进程,被init进程收养。但问题在于,这些孤儿进程里有很大一部分已经处于D状态——不可中断的睡眠,也就是——”皮克顿了顿,“僵尸化的前期。”。不可中断的睡眠,通常发生在进程等待I/O操作的时候。正常情况下,操作系统会在一段时间后强制中断,但在某些*uggy的内核版本里,进程会永远卡在D状态,连SIGKILL都杀不死。唯一的方法是重启整个系统。而在这里,重启意味着回滚一百二十七年。“所以我们要做的,”周逸凡环顾四周,“是把这些D状态的进程从等待队列里拽出来,手动给它们喂一个I/O完成的信号,让它们继续往下跑。”
皮克用那对大得离谱的眼睛盯着他:“你真的是程序员?不是路边捡的?”
“我是被裁员的前高级工程师,不是被系统踢出来的实习生。”
“行,”皮克从工装裤口袋里掏出一个比它拳头还大的平板电脑——周逸凡不知道它那点大的口袋是怎么装下这个东西的——然后啪地一下把平板展开,上面显示着一张密密麻麻的地图,“这里是斯维尔魔法学院,整个**排名第三的魔法教育机构。它在**gic_overflow线程里注册了大约两百三十个魔法进程,涉及的元素魔法、变形术、预言系等等。现在所有进程全部卡在D状态,原因统一是:等待父线程返回一个魔法值。”
“什么魔法值?”
“不知道。那个值只有父线程知道,父线程已经死了,所以所有子进程都在等一个永远不会来的返回值。”
周逸凡想了想。在编程里,这种情况有一个经典的解决方案:用默认值代替缺失的返回值。但默认值不能随便选,必须满足两个条件——第一,不能破坏下游进程的输入假设;第二,不能引发新的异常。
“我们需要找到每一个等待中的魔法进程,弄清楚它在等什么类型的返回值,然后给它一个合理的默认值。”
皮克看了看平板上的地图:“两百三十个进程,分布在整个学院的各个角落。我们得挨个找。”
“分开找?”
“分开找死得更快,”皮克说,“你是root,只有你才有权限改内存值。我只是个运维,只能读,不能写。你要是不在我旁边,我找到了也修不了。”
周逸凡叹了口气,朝着最近的一个凝固的人形生物走去。
那是一个尖耳朵的高个子,穿着深蓝色的长袍,胸口别着一个银色的徽章,上面刻着一只展翅的鹰。他的右手举在半空中,食指指着前方,嘴唇微张,像是在念咒语。周逸凡靠近了才发现,他的指尖有一团极其微弱的光,像快要熄灭的打火机的火焰,不停地闪烁。
“这是在施法过程中被冻结的,”皮克跳上周逸凡的肩膀,凑过去看了看那团光,“他在调用一个火球术函数。你看到那团光了吗?正常情况下它应该越变越大,最后脱离指尖飞出去。但现在因为父线程没有返回值,它卡在了‘请求魔法值’这一步,永远等不到燃料。”
“火球术需要什么返回值?”
“魔法量。通俗地说,就是这个火球应该有多大、多热、飞多远。这些参数由父线程的魔法溢出机制动态计算。现在父线程死了,这个火球术进程就在等一个永远不会传来的参数包。”
周逸凡低头看了看手机。屏幕上显示着recovery>提示符,光标一闪一闪的,旁边还有一行新出现的状态栏:
[location]斯维尔魔法学院,主礼堂,坐标(0x7F3A, 0x2C4*)
[process]火球术调用 #127,PID=0341,state=D,waiting_for=**gic_value_pack
[action required]
他需要给这个进程喂一个魔法值包。但他不知道正常的魔法值应该是什么。随便给一个数,可能会炸。
“皮克,正常情况下,一个火球术的魔法值包大概是什么量级?”
“因人而异,”皮克说,“魔法师的魔力上限不同,调用同一个函数,返回的参数也不同。这个施法者的魔力上限是多少——等等,我看一下。”它在平板上划了几下,“艾尔文·晨星,三阶火系魔法师,魔力上限大约在三千七百个单位左右。一个标准的火球术消耗三百到五百个单位,飞行速度取决于魔力压缩比……”
“说人话。”
“给他四百个单位,压缩比2:1,飞行距离三十米,爆炸半径一米五。这是教科书标准值。”
周逸凡在手机上输入:
set_process_param PID=0341 **gic_value_pack = {amount:400, compression:2.0, distance:30, *last_radius:1.5}
按下回车。
那团微弱的火光突然亮了起来,从暗**变成亮橙色,然后迅速膨胀到拳头大小,从艾尔文的指尖脱离,无声无息地飞了出去,撞在礼堂的墙壁上,砰的一声炸开——声音不大,像一个气球爆了。墙上的彩绘玻璃震了一下,但没碎。
周逸凡还没来得及反应,艾尔文·晨星的眼睛眨了。
尖耳朵魔法师的瞳孔从涣散状态迅速聚焦,他看到面前站着一个穿着冲锋衣、背着双肩包、手里举着一部碎屏手机的普通人类男性,以及他肩膀上那只灰蓝色的毛球。艾尔文的表情从困惑变成了警惕,又从警惕变成了震惊。
“你——”他的声音沙哑,像是很久没有说过话,“你解了我的法术锁?”
“算是吧,”周逸凡说,“你现在感觉怎么样?”
艾尔文低头看了看自己的手,握了握拳,又松开。他浑身上下检查了一遍,然后抬头看着周逸凡,眼神里多了一种说不清道不明的东西:“你是谁?你怎么能绕过魔法枢密院的权限直接修改施法参数?这不可能,整个**只有大贤者才有这个能力,而大贤者已经——”
“死了?”皮克插嘴。
艾尔文这才注意到周逸凡肩膀上的皮克,他的表情从震惊变成了惊恐:“你是……你是系统运维?我在古籍上见过你们的画像!你们是魔法诞生之前就存在的远古生物!”
“第一,我不是生物,我是运维。第二,我不是远古,我才八百多岁,在运维里还算年轻的。”皮克语气平淡,“第三,别叫我远古生物,叫我的名字,皮克。”
艾尔文看起来快要晕过去了。
周逸凡没有时间安抚一个受了惊吓的魔法师。他看了一眼手机,屏幕上已经弹出了新的提示:这个礼堂里还有三十七个等待中的进程,分布在不同的位置,冻结着不同的人。他需要一个个修。
“听着,”周逸凡对艾尔文说,“你们学院现在所有魔法都被冻结了。我来修。你帮我一个忙:告诉我这里哪些人的魔法最重要,最紧急,优先修。哪些人可以往后放。”
艾尔文深吸了几口气,努力让自己冷静下来。他的职业素养终于战胜了恐惧:“最紧急的是二楼的医疗翼。那里有十几个重伤员,他们的治疗术被冻结了,如果不尽快恢复,冻结**之后他们会立刻死去——因为治疗术只进行到一半。”
周逸凡脸色变了。他只想到修进程,没想到进程恢复之后,被暂停的副作用会立刻生效。一个被冻住的伤员,在冻结期间不会恶化,但如果治疗术只恢复了一半,冻结**的那一瞬间,伤口会继续流血,而治疗术还没有完成。
“走,”周逸凡说,“带路。”
艾尔文转身就跑,长袍的下摆在身后飘起来。周逸凡跟在他后面,皮克蹲在肩膀上,平板电脑还亮着地图。他们穿过礼堂侧门,进入一条长长的走廊。走廊两边的墙壁上也嵌着彩绘玻璃,上面的符文同样在变淡。每隔几米就有一个凝固的人——有的是端着托盘的仆人,有的是拿着书的学员,还有一个正从楼梯上摔下来的姿势极其扭曲的胖老头,悬浮在半空中,离地面还有两级台阶。
“那是我们的炼金术教授,”艾尔文一边跑一边回头看了一眼,“他每次下楼梯都会踩到自己的袍子,我们都习惯了。”
周逸凡没忍住笑了一声,但很快收了回去。
医疗翼在二楼东侧,是一个半圆形的房间,里面摆着二十多张床。大部分床上都躺着人,有的缠着绷带,有的身上插着各种管子——不是输液管,而是透明的、里面流动着发光液体的软管。最靠近门口的一张床上,躺着一个年轻的女性,她的左臂从肘部以下被什么东西整齐地切掉了,伤口处有一层淡蓝色的薄膜覆盖着,膜下面是正在缓慢生长的骨骼和肌肉。
“她的手臂被魔化兽咬断了,”艾尔文说,“治疗师用再生术帮她重铸骨骼和肌肉。再生术需要持续注入魔法值一百七十个单位每分钟,现在已经中断了——按冻结时间算,大概中断了相当于现实时间的二十几分钟。”
“冻结时间是多少?”周逸凡问皮克。
“空洞内部的冻结时间是绝对的,”皮克说,“也就是说,这些进程在空洞被隔离的那一刻就全部暂停了,外部世界的任何变化都不会影响它们。但从他们的视角看,从暂停到恢复只是眨眼之间。”
“所以他们不知道自己被冻住了?”
“不知道。对他们来说,上一秒你还在修火球术,下一秒你就出现在医疗翼,中间没有任何时间流逝。”
周逸凡松了一口气。至少他不需要解释“你们被冻结在系统底层”这种让人崩溃的事情。
他走到那个断臂女孩的床前,看了一眼手机。屏幕上显示:
[process]再生术 #44,PID=0712,state=D,waiting_for=**gic_value_continuous
连续魔法值注入。这不是一次性给一个值就能解决的,需要建立一个持续的供给通道。周逸凡从来没有在命令行里做过这种事。
“皮克,持续注入怎么搞?”
皮克从口袋里掏出一个比它手指还小的U盘——周逸凡不知道它到底有多少口袋——**了平板的接口。平板上弹出一个界面,看起来像是一个精简版的进程管理器。
“你需要创建一个魔法值管道,把父线程的职责接管过来,”皮克说,“你现在是root,你可以模拟父线程的行为。也就是说,你要以每分钟一百七十个单位的速度,持续不断地向这个再生术进程推送魔法值,直到它完成。”
“手动推送?我每分钟敲一次回车?”
“当然不是手动,你可以写一个脚本。”
周逸凡愣住了。他在系统底层,在一个由内存地址和进程构成的世界里,写脚本?
他低头看了看手机。屏幕上出现了recovery>提示符,光标后面,他可以输入任何命令。但这不是普通的shell,这是一个紧急恢复系统的调试终端,它的脚本语言是什么样的?
他试探性地输入:
for i in {1..10}; do echo "inject PID=0712 amount=170" && sleep 60; done
按下回车。屏幕上沉默了一秒钟,然后出现了一行字:
[system] com**nd not recognized: for
果然不是*ash。他需要找到这个终端支持的脚本语法。他输入了help scripting,屏幕上弹出了一段简短的文档:
recovery shell scripting:
- use repeat <n> <com**nd> to execute com**nd n times
- use loop <condition> <com**nd> for conditional loops
- use alias <name>="<com**nd>" to create shortcuts
- varia*les: $var, set var=value
行吧,虽然简陋,但够用。周逸凡输入:
repeat 60 inject PID=0712 amount=170 interval=60
这次没有报错。屏幕上出现了一行:
[system] injection scheduled. 60 iterations, 60s interval. next injection in 60s.
床边的软**,发光液体重新开始流动。断臂女孩伤口上的蓝色薄膜变亮了一些,里面的骨骼和肌肉以肉眼可见的速度生长了一小截。她的眉头微微皱了一下,像是在做梦。
周逸凡没有停下来欣赏。他转身看向艾尔文:“下一个。”
艾尔文已经从一个惊恐的魔法师变成了一个高效的导诊员。他用最快的速度在医疗翼里跑了一圈,在每一张床前停了不到两秒钟,然后回到周逸凡面前,喘着气说:“优先级从高到低:三号床,心脏衰竭,需要魔法起搏器持续输出;七号床,中毒,需要解毒术每三十秒刷新一次参数;十一号床,灵魂损伤,需要——”
“等等,”周逸凡打断他,“灵魂损伤是什么?”
“字面意思,”皮克说,“灵魂被撕裂了一部分。需要用一个锚定术把它重新固定回身体。锚定术需要的魔法值不是固定值,而是根据灵魂碎片的大小动态调整。你需要写一个自适应脚本,每十秒钟读取一次碎片大小,然后调整注入量。”
周逸凡看着手机屏幕,沉默了三秒钟。他想起自己以前写过一个自适应限流器,根据系统的实时负载动态调整请求的阈值。那个限流器上线之后,系统稳定性提升了百分之四十,然后他被裁员了。
“写就写,”他说,手指开始在屏幕上飞舞。
接下来大约一个小时——如果时间在这个空洞里还有意义的话——周逸凡在医疗翼里一个床位一个床位地修。他写了六个不同的脚本,处理了三种不同的持续注入模式,给十七个不同的进程喂了默认值。手机屏幕上的命令历史已经滚了好几屏,他的手指开始发酸,眼睛也开始干涩。
但他没有停。
皮克在旁边当他的活文档,随时告诉他每个魔法的标准参数范围、每个魔法师的魔力上限、每个治疗术的正常进度。艾尔文负责跑腿,把周逸凡从一个床位带到另一个床位,顺便在他每次修好一个人之后说一句“修好了”。
到第十七个伤员恢复的时候,周逸凡终于直起腰,转了转脖子,颈椎发出咔咔的声音。他看了看手机上的进度条:医疗翼完成度100%,整个斯维尔魔法学院完成度——12%。
十二个百分比。两百三十个进程,他修了十七个。
“还有两百一十三个,”皮克报数。
周逸凡闭上眼睛。他想起自己被裁员的那天下午,总监在会上说“公司正在进行结构性优化”,翻译过来就是“你不够便宜了”。现在他想对老天爷说同一句话:你们这个系统的结构性也太**不优化了,到处都是坑,一个僵尸线程养了三百年,派生了两百多个子进程,文档没有,注释没有,变量名还**是魔法的——你凭什么不崩?
但他说出口的是:“走吧,下一个地方是哪儿?”
“变形术教室,”艾尔文说,“三楼。那里有****学生被冻住了,他们正在上实践课。”
“什么实践课?”
“把自己变成动物。”
周逸凡想了想****半人半动物的学生被冻住的画面,决定不去想。
他跟着艾尔文走出医疗翼,沿着楼梯上到三楼。变形术教室是一间很大的阶梯教室,***站着一个头发花白的老**,举着魔杖,姿势像在指挥交响乐。阶梯座位上坐着四十六个学生——至少从座位数量上看应该是四十六个。但实际坐在座位上的,有四十三个人类、两只猫、一条狗、一个看起来像猫头鹰但体型跟人一样大的东西,以及一坨周逸凡完全无法辨认形状的灰色物质。
“那个是汉斯,”艾尔文指了指那坨灰色物质,“他每次变形都会出问题。上次他把自己的头和脚的位置搞反了,上上次他把皮肤变成了鳞片但忘了改变骨骼结构,结果整个人变成了一条没有骨头的蛇。这次看起来像是把自己变成了一团不确定状态的物质。”
“薛定谔的汉斯,”周逸凡说。
“谁?”
“一个物理学家,不是,不重要。”
周逸凡走到***,看了一眼老**。她的魔杖顶端有一颗亮蓝色的宝石,宝石里封着一个正在旋转的符文。他手机屏幕上显示:
[process]群体变形术,PID=0891,state=D,waiting_for=**gic_value_**trix
魔法值矩阵。这不是一个单一的值,而是一个四十六行乘五列的矩阵,每一行对应一个学生,每一列对应一个变形参数:目标形态、变形速度、保持时间、可逆性、副作用容忍度。
这个僵尸线程在死之前,正在批量处理四十六个学生的变形请求。它已经读完了所有人的参数,正准备把计算结果写回每个学生的进程。然后它死了。所有子进程都在等一个永远不会来的结果矩阵。
周逸凡需要自己算出这个矩阵。
“皮克,”他说,“变形术的数学原理是什么?”
“每个学生的目标形态决定了变形公式,”皮克把平板上的数据投影到空中,形成一个半透明的三维图表,“人变猫,需要压缩骨骼、改变毛发密度、调整视网膜结构、重组内耳平衡系统。这些都需要精确的魔法值映射。”
“有计算公式吗?”
“有,”皮克说,“但公式里的常数只有父线程知道。父线程死了,常数丢失了。”
周逸凡盯着空中那些密密麻麻的公式和参数,脑子里飞速运转。他想起自己在上一家公司写过一个机器学习模型,用来预测用户行为。那个模型有十七个特征、四个隐藏层、两百多个参数。他在没有文档的情况下接手了这个模型,花了三个月反向推导出了所有参数的意义。
三个月。他没有三个月。他只有现在。
“我要用逆向工程,”周逸凡说,“从每个学生当前的状态反推出变形公式的常数。”
“怎么反推?”
“你看这个学生,”周逸凡走到一个正在变成猫的学生面前,那学生已经长出了猫耳朵和胡须,但身体还是人类的,“他已经完成了变形的一部分。骨骼压缩了百分之四十,毛发密度增加了百分之六十,视网膜还没有开始调整。这说明父线程在处理他的请求时,是按照一定顺序执行的:先骨骼,再毛发,再感官。每一步的魔法值比例,可以推算出常数。”
皮克眨了眨眼睛:“你确定?”
“不确定,”周逸凡说,“但总比什么都不做强。”
他蹲下来,开始观察每一个变形中的学生,记录数据,在手机上建立一个简单的数学模型,求解常数。他花了大约四十分钟,算了三遍,得出了四组可能的常数。他选了其中一组,代入了变形公式,算出了四十六行五列的矩阵。
然后他把矩阵写进了手机:
set_process_param PID=0891 **gic_value_**trix = [46x5 **trix **ta]
按下回车。
教室里的空气突然震动了一下。***的老**手中的魔杖顶端爆出一团亮光,然后那颗蓝色宝石像心脏一样开始跳动。四十六个学生的身体同时发生变化——猫的耳朵缩了回去,狗的尾巴长了出来,那坨灰色物质开始像橡皮泥一样自我塑造,逐渐显现出一个人形。
汉斯变成了一个瘦高的金发男孩,一脸茫然地看了看自己的手,然后看了看周逸凡,张嘴说了一句话:“我是不是又变形失败了?”
“没有,”艾尔文抢在周逸凡前面说,“你成功了。你变成——你变成了你自己。这是你今年第一次成功。”
汉斯愣了一下,然后激动地从座位上跳了起来,差点摔了一跤,扶住旁边的同学才站稳。整个教室沸腾了,虽然其他学生还不完全清楚发生了什么,但看到汉斯终于从灰色物质变回了人形,所有人都自发地鼓起了掌。
周逸凡站在讲台旁边,看着这群欢呼的年轻人,心里涌起一种奇怪的感觉。他在公司写代码的时候,从来没有见过用户为他的代码鼓掌。用户只会在他代码出*ug的时候骂人,在他代码不出*ug的时候当他不存在。而现在,在这个由内存地址和进程构成的荒谬世界里,一群被冻住的魔法学生,正在为恢复正常而欢呼。
他们不知道是他修的。他们甚至不知道他们曾经被冻住过。但没关系。
“继续,”周逸凡对艾尔文说,“下一个地方。”
变形术教室之后是预言系塔楼,然后是魔药储藏室,然后是飞行训练场,然后是魔法生物饲养区。周逸凡从第一个空洞的这头走到那头,在每一个冻结的场景前停下来,读代码、猜参数、写脚本、喂值。他的手机从满电用到了百分之十二的电量,手指在碎屏上划了好几个小口子,冲锋衣的袖口磨出了毛边。
皮克在他肩膀上打了好几次盹,醒来之后继续报参数。艾尔文从一开始的惊恐变成了佩服,又从佩服变成了理所当然,开始用“那个修魔法的家伙”来称呼周逸凡。
到第二百二十九个进程的时候,周逸凡已经连续工作了将近十个小时——如果时间真的在流逝的话。他的眼睛里全是血丝,脑子里塞满了各种各样的魔法参数、进程PID、注入脚本。他站在斯维尔魔法学院的图书馆里,面前是一个冻住的古籍修复师,她正在修复一本***前的古书,书页上的文字正在从模糊变清晰的过程中被冻住了。
[process]古籍修复术,PID=1123,state=D,waiting_for=**gic_value_preservation_pack
这是倒数第二个。最后一个在图书馆的顶层——一个正在召唤元素精灵的召唤阵,那个进程需要的不是魔法值,而是一个精灵契约的签名。周逸凡已经让皮克查了标准契约模板,准备最后一起修。
他输入了古籍修复术需要的参数,按下回车。修复师的眼睛眨了一下,她低头看了看手里的书,又看了看周逸凡,礼貌地点了点头,继续工作。
周逸凡转身走向楼梯,准备去顶层修最后一个。
然后他听到了一个声音。
不是从手机里传出来的,不是皮克的声音,也不是艾尔文的声音。那个声音来自四面八方,像从墙壁里、从地板下、从天花板上同时传来,低沉、缓慢,每一个字都像敲在骨头上:
“你是***?”
周逸凡停下脚步。
“你是***,”那个声音重复了一遍,这次是陈述句,不是疑问句,“你是这个世界一直在等的***。”
“谁在说话?”周逸凡握紧了手机。
“我,”那个声音说,“是你在修的最后一个进程。”
周逸凡愣住了。最后一个进程是一个召唤阵,它在召唤什么东西?
“你不用害怕,”那个声音说,语气平静得像在念课文,“我不是什么**或神灵。我是这个世界的一个组成部分,就像重力、光、时间一样。我只是很久没有被人召唤过了,久到连我自己都忘了自己叫什么名字。”
“那你是什么?”周逸凡问。
“我是‘注释’,”那个声音说,“这个世界上每一行代码旁边的注释。你们在源代码里写下的那些说明文字,那些被删掉也不会影响运行的文字,那些被所有人忽略但只有读代码的人才会认真看的东西。我就是那个东西的具象化。”
“注释能说话?”
“注释不能说话,”那个声音说,“但你能听见我说话,因为你现在是root。只有root能听见注释。”
周逸凡想起自己在手机里写的那条签名——那行被他当作注释写进系统的字:“写了一辈子屎山代码,最后被老天爷当补丁用了。”
如果他写的注释能被系统听见,那系统里原本就存在的注释,是不是也在一直说话,只是从来没有人听见?
“你找我干什么?”周逸凡问。
“不是我找你,”注释说,“是你召唤了我。你用那些逆向工程、那些默认值、那些脚本,把我从系统的缝隙里拽了出来。因为你在做一件只有注释才能帮忙的事——你在理解这个没有文档的系统。”
“你能帮我?”
“我能告诉你这个系统的设计初衷,”注释说,“我能告诉你那些丢失的常数原来是什么,那些僵尸线程为什么要被创造出来,那些魔法值矩阵的原始公式是什么。我能告诉你一切——只要你把我从召唤阵里放出来。”
周逸凡走上楼梯,推开顶层的一扇木门,看到了那个召唤阵。
这是一个用银色线条画在地上的六芒星,每一个角上放着一颗不同颜色的宝石。六芒星的正中央,悬浮着一团没有固定形状的光,像一团被揉皱的星云。那就是注释。
“放你出来需要什么条件?”周逸凡问。
“很简单,”注释说,“把召唤阵的最后一个参数补全。那个参数原本应该是一个灵魂印记,用来绑定召唤者和被召唤者之间的契约。父线程死了,这个灵魂印记就丢失了。你可以用自己的灵魂印记代替。”
“用我的灵魂?听起来不像一个简单的事情。”
“很简单,”注释说,“你只需要在手机上输入一行命令:**nd_soul PID=1133 with_current_user。按回车,我就出来了。然后我可以帮你修好这个世界剩下的所有空洞——不只是这一个,而是整个系统里成百上千个空洞。我一个注释就能搞定。”
周逸凡低头看着手机屏幕。确实,help命令里有一条**nd_soul,说明文档写的是“将当前用户与指定进程绑定,建立永久性契约”。
他正要输入,皮克突然在他肩膀上狠狠地揪了他耳朵一下。
“别信它,”皮克的声音又尖又急,“注释是系统里最危险的东西。它看起来什么都知道,但它只会告诉你它想让你知道的事情。而且——一个灵魂印记只能绑定一次,绑定了就不能解绑。你绑了它,你就永远跟它连在一起了,你死了它都不会放手。你知道这意味着什么吗?”
“意味着什么?”
“意味着你会变成注释的一部分,”皮克说,“你不是在召唤它,你是在把自己献给它。”
注释的声音再次响起,这次带着一丝笑意:“皮克,你还是这么不信任我。***了,你做了***运维,你什么时候见我害过***?”
“你没害过***是因为*****本没有***!”皮克吼道,“你是注释,你生来就是为了被忽略的!现在突然来了一个root,你就想把自己绑上去——你这不是害人是什么?”
周逸凡站在召唤阵前,手机屏幕上的光标一闪一闪的,等着他输入命令。他的手指悬在屏幕上方,离那行命令只有一厘米的距离。
他看了看注释——那团被揉皱的星云,安静地悬浮在六芒星中央,发出柔和的光。他又看了看皮克——那只灰蓝色的小东西,正瞪大了眼睛看着他,瞳孔缩成了一条竖线,耳朵紧紧地贴在脑袋上,像一只炸了毛的猫。
“我先不绑定,”周逸凡说,“我先把这个学院修完。最后一个进程——就是这个召唤阵——我用默认参数把它完成,把你放出来,但不绑定灵魂。你愿意吗?”
注释沉默了三秒钟。
“行,”它说,“用默认参数也行。但默认参数只能维持三十天。三十天之后,契约失效,我会重新被封印回召唤阵。到时候你如果不来续约,我就永远出不来了。”
“三十天够了,”周逸凡说,“三十天之内我会回来的。”
他输入了默认参数,按下回车。
六芒星亮了起来,每一颗宝石都射出一道光线,汇聚到中央的星云上。星云开始旋转,越转越快,最后像一个漩涡一样收缩、凝聚、变成了一颗豌豆大小的银色珠子,落在地上,滚了两圈,停在了周逸凡的鞋尖前面。
皮克从肩膀上跳下来,用两根手指捏起那颗珠子,举到眼前看了看,然后塞进了工装裤的口袋里。
“我帮你保管,”皮克说,“你不能碰它,至少在三十天内不能。”
周逸凡没有反对。
他看了看手机,斯维尔魔法学院的进度条终于走到了100%。屏幕上弹出了一行绿色的字:
[system]斯维尔魔法学院恢复完成。所有进程已修复。空洞正在收缩。
周围的空气开始震动,图书馆的墙壁变得透明,像冰块在融化。他透过墙壁看到了外面的走廊、楼梯、礼堂,然后看到了更外面的灰色虚空。整个空洞像一个肥皂泡一样在收缩,把他和皮克、艾尔文、以及所有他修复过的人,一起吐了出来。
他们回到了那个发光的走廊。
艾尔文站在走廊里,茫然地看着四周:“这是哪儿?”
“不重要,”周逸凡说,“你回去吧。你的学院已经恢复正常了。”
艾尔文张了张嘴,想说什么,但没说出来。他深深地看了周逸凡一眼,然后像被什么东西吸走了一样,嗖地消失了。
皮克蹲在周逸凡肩膀上,看着手机屏幕上的新消息:
[system]空洞#1已关闭。剩余空洞数量:无法计数。建议先吃顿饭。
“它建议你吃饭,”皮克说。
周逸凡摸了摸肚子,这才发现自己已经饿得前胸贴后背了。他从双肩包里掏出一个被压扁了的面包——还是昨天从公司带出来的,已经硬得像砖头。他掰了一块塞进嘴里,嚼了嚼,咽了下去。
“不好吃,”他说。
“在系统底层你还能指望什么?”皮克说,“不过我可以告诉你一个好消息。”
“什么?”
“第一个空洞是最难的。后面的空洞,难度会逐级降低。因为你每修一个空洞,就会多积累一点经验,也会多获得一点系统权限。等你修到第十个空洞的时候,你可能已经能用语音控制手机了。等你修到第五十个的时候,你可能挥挥手就能修好一个进程。”
“那我修完所有空洞之后呢?”
皮克看了他一眼,耳朵抖了一下:“你真想知道?”
“说。”
“修完所有空洞之后,你会成为这个世界的新内核,”皮克说,“不是***,不是root,而是内核本身。你会取代那个已经死了三百多年的父线程,成为所有魔法、所有进程、所有生命的底层逻辑。那时候你就不是‘在修系统’了,你就是系统。”
周逸凡又掰了一块硬面包塞进嘴里,慢慢地嚼着。
“听起来像一个比裁员更糟糕的工作,”他说。
皮克没有回答,只是从他肩膀上跳下来,沿着发光的走廊往前走了几步,然后回头看他:“走吧,第二个空洞在东边。大约三十分钟路程。你可以边走边吃。”
周逸凡把剩下的面包塞回包里,跟上了皮克的脚步。
发光的走廊在他身后慢慢暗了下去,像一条刚刚走过的路,正在被黑暗吞没。他不知道这条走廊有多长,不知道还有多少个空洞在等着他,不知道自己会不会在修完所有空洞之后真的变成那个所谓的内核。
但他知道一件事:他现在有一份工作,一份不会裁员的工作,一份如果他不干整个世界就会崩溃的工作。
讽刺。
皮克用那对大得离谱的眼睛盯着他:“你真的是程序员?不是路边捡的?”
“我是被裁员的前高级工程师,不是被系统踢出来的实习生。”
“行,”皮克从工装裤口袋里掏出一个比它拳头还大的平板电脑——周逸凡不知道它那点大的口袋是怎么装下这个东西的——然后啪地一下把平板展开,上面显示着一张密密麻麻的地图,“这里是斯维尔魔法学院,整个**排名第三的魔法教育机构。它在**gic_overflow线程里注册了大约两百三十个魔法进程,涉及的元素魔法、变形术、预言系等等。现在所有进程全部卡在D状态,原因统一是:等待父线程返回一个魔法值。”
“什么魔法值?”
“不知道。那个值只有父线程知道,父线程已经死了,所以所有子进程都在等一个永远不会来的返回值。”
周逸凡想了想。在编程里,这种情况有一个经典的解决方案:用默认值代替缺失的返回值。但默认值不能随便选,必须满足两个条件——第一,不能破坏下游进程的输入假设;第二,不能引发新的异常。
“我们需要找到每一个等待中的魔法进程,弄清楚它在等什么类型的返回值,然后给它一个合理的默认值。”
皮克看了看平板上的地图:“两百三十个进程,分布在整个学院的各个角落。我们得挨个找。”
“分开找?”
“分开找死得更快,”皮克说,“你是root,只有你才有权限改内存值。我只是个运维,只能读,不能写。你要是不在我旁边,我找到了也修不了。”
周逸凡叹了口气,朝着最近的一个凝固的人形生物走去。
那是一个尖耳朵的高个子,穿着深蓝色的长袍,胸口别着一个银色的徽章,上面刻着一只展翅的鹰。他的右手举在半空中,食指指着前方,嘴唇微张,像是在念咒语。周逸凡靠近了才发现,他的指尖有一团极其微弱的光,像快要熄灭的打火机的火焰,不停地闪烁。
“这是在施法过程中被冻结的,”皮克跳上周逸凡的肩膀,凑过去看了看那团光,“他在调用一个火球术函数。你看到那团光了吗?正常情况下它应该越变越大,最后脱离指尖飞出去。但现在因为父线程没有返回值,它卡在了‘请求魔法值’这一步,永远等不到燃料。”
“火球术需要什么返回值?”
“魔法量。通俗地说,就是这个火球应该有多大、多热、飞多远。这些参数由父线程的魔法溢出机制动态计算。现在父线程死了,这个火球术进程就在等一个永远不会传来的参数包。”
周逸凡低头看了看手机。屏幕上显示着recovery>提示符,光标一闪一闪的,旁边还有一行新出现的状态栏:
[location]斯维尔魔法学院,主礼堂,坐标(0x7F3A, 0x2C4*)
[process]火球术调用 #127,PID=0341,state=D,waiting_for=**gic_value_pack
[action required]
他需要给这个进程喂一个魔法值包。但他不知道正常的魔法值应该是什么。随便给一个数,可能会炸。
“皮克,正常情况下,一个火球术的魔法值包大概是什么量级?”
“因人而异,”皮克说,“魔法师的魔力上限不同,调用同一个函数,返回的参数也不同。这个施法者的魔力上限是多少——等等,我看一下。”它在平板上划了几下,“艾尔文·晨星,三阶火系魔法师,魔力上限大约在三千七百个单位左右。一个标准的火球术消耗三百到五百个单位,飞行速度取决于魔力压缩比……”
“说人话。”
“给他四百个单位,压缩比2:1,飞行距离三十米,爆炸半径一米五。这是教科书标准值。”
周逸凡在手机上输入:
set_process_param PID=0341 **gic_value_pack = {amount:400, compression:2.0, distance:30, *last_radius:1.5}
按下回车。
那团微弱的火光突然亮了起来,从暗**变成亮橙色,然后迅速膨胀到拳头大小,从艾尔文的指尖脱离,无声无息地飞了出去,撞在礼堂的墙壁上,砰的一声炸开——声音不大,像一个气球爆了。墙上的彩绘玻璃震了一下,但没碎。
周逸凡还没来得及反应,艾尔文·晨星的眼睛眨了。
尖耳朵魔法师的瞳孔从涣散状态迅速聚焦,他看到面前站着一个穿着冲锋衣、背着双肩包、手里举着一部碎屏手机的普通人类男性,以及他肩膀上那只灰蓝色的毛球。艾尔文的表情从困惑变成了警惕,又从警惕变成了震惊。
“你——”他的声音沙哑,像是很久没有说过话,“你解了我的法术锁?”
“算是吧,”周逸凡说,“你现在感觉怎么样?”
艾尔文低头看了看自己的手,握了握拳,又松开。他浑身上下检查了一遍,然后抬头看着周逸凡,眼神里多了一种说不清道不明的东西:“你是谁?你怎么能绕过魔法枢密院的权限直接修改施法参数?这不可能,整个**只有大贤者才有这个能力,而大贤者已经——”
“死了?”皮克插嘴。
艾尔文这才注意到周逸凡肩膀上的皮克,他的表情从震惊变成了惊恐:“你是……你是系统运维?我在古籍上见过你们的画像!你们是魔法诞生之前就存在的远古生物!”
“第一,我不是生物,我是运维。第二,我不是远古,我才八百多岁,在运维里还算年轻的。”皮克语气平淡,“第三,别叫我远古生物,叫我的名字,皮克。”
艾尔文看起来快要晕过去了。
周逸凡没有时间安抚一个受了惊吓的魔法师。他看了一眼手机,屏幕上已经弹出了新的提示:这个礼堂里还有三十七个等待中的进程,分布在不同的位置,冻结着不同的人。他需要一个个修。
“听着,”周逸凡对艾尔文说,“你们学院现在所有魔法都被冻结了。我来修。你帮我一个忙:告诉我这里哪些人的魔法最重要,最紧急,优先修。哪些人可以往后放。”
艾尔文深吸了几口气,努力让自己冷静下来。他的职业素养终于战胜了恐惧:“最紧急的是二楼的医疗翼。那里有十几个重伤员,他们的治疗术被冻结了,如果不尽快恢复,冻结**之后他们会立刻死去——因为治疗术只进行到一半。”
周逸凡脸色变了。他只想到修进程,没想到进程恢复之后,被暂停的副作用会立刻生效。一个被冻住的伤员,在冻结期间不会恶化,但如果治疗术只恢复了一半,冻结**的那一瞬间,伤口会继续流血,而治疗术还没有完成。
“走,”周逸凡说,“带路。”
艾尔文转身就跑,长袍的下摆在身后飘起来。周逸凡跟在他后面,皮克蹲在肩膀上,平板电脑还亮着地图。他们穿过礼堂侧门,进入一条长长的走廊。走廊两边的墙壁上也嵌着彩绘玻璃,上面的符文同样在变淡。每隔几米就有一个凝固的人——有的是端着托盘的仆人,有的是拿着书的学员,还有一个正从楼梯上摔下来的姿势极其扭曲的胖老头,悬浮在半空中,离地面还有两级台阶。
“那是我们的炼金术教授,”艾尔文一边跑一边回头看了一眼,“他每次下楼梯都会踩到自己的袍子,我们都习惯了。”
周逸凡没忍住笑了一声,但很快收了回去。
医疗翼在二楼东侧,是一个半圆形的房间,里面摆着二十多张床。大部分床上都躺着人,有的缠着绷带,有的身上插着各种管子——不是输液管,而是透明的、里面流动着发光液体的软管。最靠近门口的一张床上,躺着一个年轻的女性,她的左臂从肘部以下被什么东西整齐地切掉了,伤口处有一层淡蓝色的薄膜覆盖着,膜下面是正在缓慢生长的骨骼和肌肉。
“她的手臂被魔化兽咬断了,”艾尔文说,“治疗师用再生术帮她重铸骨骼和肌肉。再生术需要持续注入魔法值一百七十个单位每分钟,现在已经中断了——按冻结时间算,大概中断了相当于现实时间的二十几分钟。”
“冻结时间是多少?”周逸凡问皮克。
“空洞内部的冻结时间是绝对的,”皮克说,“也就是说,这些进程在空洞被隔离的那一刻就全部暂停了,外部世界的任何变化都不会影响它们。但从他们的视角看,从暂停到恢复只是眨眼之间。”
“所以他们不知道自己被冻住了?”
“不知道。对他们来说,上一秒你还在修火球术,下一秒你就出现在医疗翼,中间没有任何时间流逝。”
周逸凡松了一口气。至少他不需要解释“你们被冻结在系统底层”这种让人崩溃的事情。
他走到那个断臂女孩的床前,看了一眼手机。屏幕上显示:
[process]再生术 #44,PID=0712,state=D,waiting_for=**gic_value_continuous
连续魔法值注入。这不是一次性给一个值就能解决的,需要建立一个持续的供给通道。周逸凡从来没有在命令行里做过这种事。
“皮克,持续注入怎么搞?”
皮克从口袋里掏出一个比它手指还小的U盘——周逸凡不知道它到底有多少口袋——**了平板的接口。平板上弹出一个界面,看起来像是一个精简版的进程管理器。
“你需要创建一个魔法值管道,把父线程的职责接管过来,”皮克说,“你现在是root,你可以模拟父线程的行为。也就是说,你要以每分钟一百七十个单位的速度,持续不断地向这个再生术进程推送魔法值,直到它完成。”
“手动推送?我每分钟敲一次回车?”
“当然不是手动,你可以写一个脚本。”
周逸凡愣住了。他在系统底层,在一个由内存地址和进程构成的世界里,写脚本?
他低头看了看手机。屏幕上出现了recovery>提示符,光标后面,他可以输入任何命令。但这不是普通的shell,这是一个紧急恢复系统的调试终端,它的脚本语言是什么样的?
他试探性地输入:
for i in {1..10}; do echo "inject PID=0712 amount=170" && sleep 60; done
按下回车。屏幕上沉默了一秒钟,然后出现了一行字:
[system] com**nd not recognized: for
果然不是*ash。他需要找到这个终端支持的脚本语法。他输入了help scripting,屏幕上弹出了一段简短的文档:
recovery shell scripting:
- use repeat <n> <com**nd> to execute com**nd n times
- use loop <condition> <com**nd> for conditional loops
- use alias <name>="<com**nd>" to create shortcuts
- varia*les: $var, set var=value
行吧,虽然简陋,但够用。周逸凡输入:
repeat 60 inject PID=0712 amount=170 interval=60
这次没有报错。屏幕上出现了一行:
[system] injection scheduled. 60 iterations, 60s interval. next injection in 60s.
床边的软**,发光液体重新开始流动。断臂女孩伤口上的蓝色薄膜变亮了一些,里面的骨骼和肌肉以肉眼可见的速度生长了一小截。她的眉头微微皱了一下,像是在做梦。
周逸凡没有停下来欣赏。他转身看向艾尔文:“下一个。”
艾尔文已经从一个惊恐的魔法师变成了一个高效的导诊员。他用最快的速度在医疗翼里跑了一圈,在每一张床前停了不到两秒钟,然后回到周逸凡面前,喘着气说:“优先级从高到低:三号床,心脏衰竭,需要魔法起搏器持续输出;七号床,中毒,需要解毒术每三十秒刷新一次参数;十一号床,灵魂损伤,需要——”
“等等,”周逸凡打断他,“灵魂损伤是什么?”
“字面意思,”皮克说,“灵魂被撕裂了一部分。需要用一个锚定术把它重新固定回身体。锚定术需要的魔法值不是固定值,而是根据灵魂碎片的大小动态调整。你需要写一个自适应脚本,每十秒钟读取一次碎片大小,然后调整注入量。”
周逸凡看着手机屏幕,沉默了三秒钟。他想起自己以前写过一个自适应限流器,根据系统的实时负载动态调整请求的阈值。那个限流器上线之后,系统稳定性提升了百分之四十,然后他被裁员了。
“写就写,”他说,手指开始在屏幕上飞舞。
接下来大约一个小时——如果时间在这个空洞里还有意义的话——周逸凡在医疗翼里一个床位一个床位地修。他写了六个不同的脚本,处理了三种不同的持续注入模式,给十七个不同的进程喂了默认值。手机屏幕上的命令历史已经滚了好几屏,他的手指开始发酸,眼睛也开始干涩。
但他没有停。
皮克在旁边当他的活文档,随时告诉他每个魔法的标准参数范围、每个魔法师的魔力上限、每个治疗术的正常进度。艾尔文负责跑腿,把周逸凡从一个床位带到另一个床位,顺便在他每次修好一个人之后说一句“修好了”。
到第十七个伤员恢复的时候,周逸凡终于直起腰,转了转脖子,颈椎发出咔咔的声音。他看了看手机上的进度条:医疗翼完成度100%,整个斯维尔魔法学院完成度——12%。
十二个百分比。两百三十个进程,他修了十七个。
“还有两百一十三个,”皮克报数。
周逸凡闭上眼睛。他想起自己被裁员的那天下午,总监在会上说“公司正在进行结构性优化”,翻译过来就是“你不够便宜了”。现在他想对老天爷说同一句话:你们这个系统的结构性也太**不优化了,到处都是坑,一个僵尸线程养了三百年,派生了两百多个子进程,文档没有,注释没有,变量名还**是魔法的——你凭什么不崩?
但他说出口的是:“走吧,下一个地方是哪儿?”
“变形术教室,”艾尔文说,“三楼。那里有****学生被冻住了,他们正在上实践课。”
“什么实践课?”
“把自己变成动物。”
周逸凡想了想****半人半动物的学生被冻住的画面,决定不去想。
他跟着艾尔文走出医疗翼,沿着楼梯上到三楼。变形术教室是一间很大的阶梯教室,***站着一个头发花白的老**,举着魔杖,姿势像在指挥交响乐。阶梯座位上坐着四十六个学生——至少从座位数量上看应该是四十六个。但实际坐在座位上的,有四十三个人类、两只猫、一条狗、一个看起来像猫头鹰但体型跟人一样大的东西,以及一坨周逸凡完全无法辨认形状的灰色物质。
“那个是汉斯,”艾尔文指了指那坨灰色物质,“他每次变形都会出问题。上次他把自己的头和脚的位置搞反了,上上次他把皮肤变成了鳞片但忘了改变骨骼结构,结果整个人变成了一条没有骨头的蛇。这次看起来像是把自己变成了一团不确定状态的物质。”
“薛定谔的汉斯,”周逸凡说。
“谁?”
“一个物理学家,不是,不重要。”
周逸凡走到***,看了一眼老**。她的魔杖顶端有一颗亮蓝色的宝石,宝石里封着一个正在旋转的符文。他手机屏幕上显示:
[process]群体变形术,PID=0891,state=D,waiting_for=**gic_value_**trix
魔法值矩阵。这不是一个单一的值,而是一个四十六行乘五列的矩阵,每一行对应一个学生,每一列对应一个变形参数:目标形态、变形速度、保持时间、可逆性、副作用容忍度。
这个僵尸线程在死之前,正在批量处理四十六个学生的变形请求。它已经读完了所有人的参数,正准备把计算结果写回每个学生的进程。然后它死了。所有子进程都在等一个永远不会来的结果矩阵。
周逸凡需要自己算出这个矩阵。
“皮克,”他说,“变形术的数学原理是什么?”
“每个学生的目标形态决定了变形公式,”皮克把平板上的数据投影到空中,形成一个半透明的三维图表,“人变猫,需要压缩骨骼、改变毛发密度、调整视网膜结构、重组内耳平衡系统。这些都需要精确的魔法值映射。”
“有计算公式吗?”
“有,”皮克说,“但公式里的常数只有父线程知道。父线程死了,常数丢失了。”
周逸凡盯着空中那些密密麻麻的公式和参数,脑子里飞速运转。他想起自己在上一家公司写过一个机器学习模型,用来预测用户行为。那个模型有十七个特征、四个隐藏层、两百多个参数。他在没有文档的情况下接手了这个模型,花了三个月反向推导出了所有参数的意义。
三个月。他没有三个月。他只有现在。
“我要用逆向工程,”周逸凡说,“从每个学生当前的状态反推出变形公式的常数。”
“怎么反推?”
“你看这个学生,”周逸凡走到一个正在变成猫的学生面前,那学生已经长出了猫耳朵和胡须,但身体还是人类的,“他已经完成了变形的一部分。骨骼压缩了百分之四十,毛发密度增加了百分之六十,视网膜还没有开始调整。这说明父线程在处理他的请求时,是按照一定顺序执行的:先骨骼,再毛发,再感官。每一步的魔法值比例,可以推算出常数。”
皮克眨了眨眼睛:“你确定?”
“不确定,”周逸凡说,“但总比什么都不做强。”
他蹲下来,开始观察每一个变形中的学生,记录数据,在手机上建立一个简单的数学模型,求解常数。他花了大约四十分钟,算了三遍,得出了四组可能的常数。他选了其中一组,代入了变形公式,算出了四十六行五列的矩阵。
然后他把矩阵写进了手机:
set_process_param PID=0891 **gic_value_**trix = [46x5 **trix **ta]
按下回车。
教室里的空气突然震动了一下。***的老**手中的魔杖顶端爆出一团亮光,然后那颗蓝色宝石像心脏一样开始跳动。四十六个学生的身体同时发生变化——猫的耳朵缩了回去,狗的尾巴长了出来,那坨灰色物质开始像橡皮泥一样自我塑造,逐渐显现出一个人形。
汉斯变成了一个瘦高的金发男孩,一脸茫然地看了看自己的手,然后看了看周逸凡,张嘴说了一句话:“我是不是又变形失败了?”
“没有,”艾尔文抢在周逸凡前面说,“你成功了。你变成——你变成了你自己。这是你今年第一次成功。”
汉斯愣了一下,然后激动地从座位上跳了起来,差点摔了一跤,扶住旁边的同学才站稳。整个教室沸腾了,虽然其他学生还不完全清楚发生了什么,但看到汉斯终于从灰色物质变回了人形,所有人都自发地鼓起了掌。
周逸凡站在讲台旁边,看着这群欢呼的年轻人,心里涌起一种奇怪的感觉。他在公司写代码的时候,从来没有见过用户为他的代码鼓掌。用户只会在他代码出*ug的时候骂人,在他代码不出*ug的时候当他不存在。而现在,在这个由内存地址和进程构成的荒谬世界里,一群被冻住的魔法学生,正在为恢复正常而欢呼。
他们不知道是他修的。他们甚至不知道他们曾经被冻住过。但没关系。
“继续,”周逸凡对艾尔文说,“下一个地方。”
变形术教室之后是预言系塔楼,然后是魔药储藏室,然后是飞行训练场,然后是魔法生物饲养区。周逸凡从第一个空洞的这头走到那头,在每一个冻结的场景前停下来,读代码、猜参数、写脚本、喂值。他的手机从满电用到了百分之十二的电量,手指在碎屏上划了好几个小口子,冲锋衣的袖口磨出了毛边。
皮克在他肩膀上打了好几次盹,醒来之后继续报参数。艾尔文从一开始的惊恐变成了佩服,又从佩服变成了理所当然,开始用“那个修魔法的家伙”来称呼周逸凡。
到第二百二十九个进程的时候,周逸凡已经连续工作了将近十个小时——如果时间真的在流逝的话。他的眼睛里全是血丝,脑子里塞满了各种各样的魔法参数、进程PID、注入脚本。他站在斯维尔魔法学院的图书馆里,面前是一个冻住的古籍修复师,她正在修复一本***前的古书,书页上的文字正在从模糊变清晰的过程中被冻住了。
[process]古籍修复术,PID=1123,state=D,waiting_for=**gic_value_preservation_pack
这是倒数第二个。最后一个在图书馆的顶层——一个正在召唤元素精灵的召唤阵,那个进程需要的不是魔法值,而是一个精灵契约的签名。周逸凡已经让皮克查了标准契约模板,准备最后一起修。
他输入了古籍修复术需要的参数,按下回车。修复师的眼睛眨了一下,她低头看了看手里的书,又看了看周逸凡,礼貌地点了点头,继续工作。
周逸凡转身走向楼梯,准备去顶层修最后一个。
然后他听到了一个声音。
不是从手机里传出来的,不是皮克的声音,也不是艾尔文的声音。那个声音来自四面八方,像从墙壁里、从地板下、从天花板上同时传来,低沉、缓慢,每一个字都像敲在骨头上:
“你是***?”
周逸凡停下脚步。
“你是***,”那个声音重复了一遍,这次是陈述句,不是疑问句,“你是这个世界一直在等的***。”
“谁在说话?”周逸凡握紧了手机。
“我,”那个声音说,“是你在修的最后一个进程。”
周逸凡愣住了。最后一个进程是一个召唤阵,它在召唤什么东西?
“你不用害怕,”那个声音说,语气平静得像在念课文,“我不是什么**或神灵。我是这个世界的一个组成部分,就像重力、光、时间一样。我只是很久没有被人召唤过了,久到连我自己都忘了自己叫什么名字。”
“那你是什么?”周逸凡问。
“我是‘注释’,”那个声音说,“这个世界上每一行代码旁边的注释。你们在源代码里写下的那些说明文字,那些被删掉也不会影响运行的文字,那些被所有人忽略但只有读代码的人才会认真看的东西。我就是那个东西的具象化。”
“注释能说话?”
“注释不能说话,”那个声音说,“但你能听见我说话,因为你现在是root。只有root能听见注释。”
周逸凡想起自己在手机里写的那条签名——那行被他当作注释写进系统的字:“写了一辈子屎山代码,最后被老天爷当补丁用了。”
如果他写的注释能被系统听见,那系统里原本就存在的注释,是不是也在一直说话,只是从来没有人听见?
“你找我干什么?”周逸凡问。
“不是我找你,”注释说,“是你召唤了我。你用那些逆向工程、那些默认值、那些脚本,把我从系统的缝隙里拽了出来。因为你在做一件只有注释才能帮忙的事——你在理解这个没有文档的系统。”
“你能帮我?”
“我能告诉你这个系统的设计初衷,”注释说,“我能告诉你那些丢失的常数原来是什么,那些僵尸线程为什么要被创造出来,那些魔法值矩阵的原始公式是什么。我能告诉你一切——只要你把我从召唤阵里放出来。”
周逸凡走上楼梯,推开顶层的一扇木门,看到了那个召唤阵。
这是一个用银色线条画在地上的六芒星,每一个角上放着一颗不同颜色的宝石。六芒星的正中央,悬浮着一团没有固定形状的光,像一团被揉皱的星云。那就是注释。
“放你出来需要什么条件?”周逸凡问。
“很简单,”注释说,“把召唤阵的最后一个参数补全。那个参数原本应该是一个灵魂印记,用来绑定召唤者和被召唤者之间的契约。父线程死了,这个灵魂印记就丢失了。你可以用自己的灵魂印记代替。”
“用我的灵魂?听起来不像一个简单的事情。”
“很简单,”注释说,“你只需要在手机上输入一行命令:**nd_soul PID=1133 with_current_user。按回车,我就出来了。然后我可以帮你修好这个世界剩下的所有空洞——不只是这一个,而是整个系统里成百上千个空洞。我一个注释就能搞定。”
周逸凡低头看着手机屏幕。确实,help命令里有一条**nd_soul,说明文档写的是“将当前用户与指定进程绑定,建立永久性契约”。
他正要输入,皮克突然在他肩膀上狠狠地揪了他耳朵一下。
“别信它,”皮克的声音又尖又急,“注释是系统里最危险的东西。它看起来什么都知道,但它只会告诉你它想让你知道的事情。而且——一个灵魂印记只能绑定一次,绑定了就不能解绑。你绑了它,你就永远跟它连在一起了,你死了它都不会放手。你知道这意味着什么吗?”
“意味着什么?”
“意味着你会变成注释的一部分,”皮克说,“你不是在召唤它,你是在把自己献给它。”
注释的声音再次响起,这次带着一丝笑意:“皮克,你还是这么不信任我。***了,你做了***运维,你什么时候见我害过***?”
“你没害过***是因为*****本没有***!”皮克吼道,“你是注释,你生来就是为了被忽略的!现在突然来了一个root,你就想把自己绑上去——你这不是害人是什么?”
周逸凡站在召唤阵前,手机屏幕上的光标一闪一闪的,等着他输入命令。他的手指悬在屏幕上方,离那行命令只有一厘米的距离。
他看了看注释——那团被揉皱的星云,安静地悬浮在六芒星中央,发出柔和的光。他又看了看皮克——那只灰蓝色的小东西,正瞪大了眼睛看着他,瞳孔缩成了一条竖线,耳朵紧紧地贴在脑袋上,像一只炸了毛的猫。
“我先不绑定,”周逸凡说,“我先把这个学院修完。最后一个进程——就是这个召唤阵——我用默认参数把它完成,把你放出来,但不绑定灵魂。你愿意吗?”
注释沉默了三秒钟。
“行,”它说,“用默认参数也行。但默认参数只能维持三十天。三十天之后,契约失效,我会重新被封印回召唤阵。到时候你如果不来续约,我就永远出不来了。”
“三十天够了,”周逸凡说,“三十天之内我会回来的。”
他输入了默认参数,按下回车。
六芒星亮了起来,每一颗宝石都射出一道光线,汇聚到中央的星云上。星云开始旋转,越转越快,最后像一个漩涡一样收缩、凝聚、变成了一颗豌豆大小的银色珠子,落在地上,滚了两圈,停在了周逸凡的鞋尖前面。
皮克从肩膀上跳下来,用两根手指捏起那颗珠子,举到眼前看了看,然后塞进了工装裤的口袋里。
“我帮你保管,”皮克说,“你不能碰它,至少在三十天内不能。”
周逸凡没有反对。
他看了看手机,斯维尔魔法学院的进度条终于走到了100%。屏幕上弹出了一行绿色的字:
[system]斯维尔魔法学院恢复完成。所有进程已修复。空洞正在收缩。
周围的空气开始震动,图书馆的墙壁变得透明,像冰块在融化。他透过墙壁看到了外面的走廊、楼梯、礼堂,然后看到了更外面的灰色虚空。整个空洞像一个肥皂泡一样在收缩,把他和皮克、艾尔文、以及所有他修复过的人,一起吐了出来。
他们回到了那个发光的走廊。
艾尔文站在走廊里,茫然地看着四周:“这是哪儿?”
“不重要,”周逸凡说,“你回去吧。你的学院已经恢复正常了。”
艾尔文张了张嘴,想说什么,但没说出来。他深深地看了周逸凡一眼,然后像被什么东西吸走了一样,嗖地消失了。
皮克蹲在周逸凡肩膀上,看着手机屏幕上的新消息:
[system]空洞#1已关闭。剩余空洞数量:无法计数。建议先吃顿饭。
“它建议你吃饭,”皮克说。
周逸凡摸了摸肚子,这才发现自己已经饿得前胸贴后背了。他从双肩包里掏出一个被压扁了的面包——还是昨天从公司带出来的,已经硬得像砖头。他掰了一块塞进嘴里,嚼了嚼,咽了下去。
“不好吃,”他说。
“在系统底层你还能指望什么?”皮克说,“不过我可以告诉你一个好消息。”
“什么?”
“第一个空洞是最难的。后面的空洞,难度会逐级降低。因为你每修一个空洞,就会多积累一点经验,也会多获得一点系统权限。等你修到第十个空洞的时候,你可能已经能用语音控制手机了。等你修到第五十个的时候,你可能挥挥手就能修好一个进程。”
“那我修完所有空洞之后呢?”
皮克看了他一眼,耳朵抖了一下:“你真想知道?”
“说。”
“修完所有空洞之后,你会成为这个世界的新内核,”皮克说,“不是***,不是root,而是内核本身。你会取代那个已经死了三百多年的父线程,成为所有魔法、所有进程、所有生命的底层逻辑。那时候你就不是‘在修系统’了,你就是系统。”
周逸凡又掰了一块硬面包塞进嘴里,慢慢地嚼着。
“听起来像一个比裁员更糟糕的工作,”他说。
皮克没有回答,只是从他肩膀上跳下来,沿着发光的走廊往前走了几步,然后回头看他:“走吧,第二个空洞在东边。大约三十分钟路程。你可以边走边吃。”
周逸凡把剩下的面包塞回包里,跟上了皮克的脚步。
发光的走廊在他身后慢慢暗了下去,像一条刚刚走过的路,正在被黑暗吞没。他不知道这条走廊有多长,不知道还有多少个空洞在等着他,不知道自己会不会在修完所有空洞之后真的变成那个所谓的内核。
但他知道一件事:他现在有一份工作,一份不会裁员的工作,一份如果他不干整个世界就会崩溃的工作。
讽刺。
阅读下一章(解锁全文)
点击即可畅读完整版全部内容
相关书籍
友情链接