第2章
透明的,不是空的
第一個空洞——魔法學院------------------------------------------,邊緣的暗紅色光芒像余燼一樣忽明忽暗。周逸凡站在它面前,能感覺到一股吸力,像站在地鐵站臺邊緣,列車呼嘯而過時帶起的那股風,但方向是反的——不是往外推,而是往里拽?!澳阆冗M還是我先進?”皮克問?!澳?**的經驗是用來問這種問題的嗎?我***沒進過空洞,”皮克理直氣壯,“以前系統出問題都是直接回滾,誰**在線修復啊。你當這是寫博客呢,隨便改?”,把手機舉在胸前當手電筒,一腳邁進了黑洞。,他感覺自己像是被一個巨大的篩子過了一遍。不是疼,是一種說不上來的不對勁——像是身體里所有的零件都被拆下來清洗了一遍,然后又重新裝回去,但裝的時候有幾個螺絲擰錯了位置。他低頭看了看自己的手,手還在,五根手指,指甲蓋下面的月牙白也還在。他松了一口氣。。,高得看不到頂,穹頂上原本應該繪滿壁畫的位置,現在是一片灰白色的空白,像一張被擦干凈的黑板。四周的墻壁上嵌著彩繪玻璃窗,但窗戶上畫的不是什么圣徒或天使,而是一行行發光的符文,像代碼又像咒語。那些符文正在以肉眼可見的速度變淡,像墨水在紙上洇開然后消失。——不對,不全是人。有長著尖耳朵的高個子,有渾身覆蓋鱗片、像蜥蜴一樣直立行走的生物,還有幾個飄浮在半空中、半透明的水母狀東西,它們的觸手末端各頂著一顆發光的小球。所有這些生物都一動不動,像雕塑一樣凝固在原地。不是被冰凍的那種凝固,而是像視頻暫停了,他們的衣角還保持著被風吹起的弧度,眼睛里還反射著禮堂穹頂上的光,但光已經不在了。“暫停了?”周逸凡問?!皟鼋Y了,”皮克從他肩膀上跳下來,落在地上幾乎沒有聲音,“這個空洞所在的地址空間被隔離了,里面的所有進程都被掛起。你看到的這些——這些生物,”周逸凡接過話,“是這個世界的進程實例。精確地說,是[**gic_overflow]僵尸線程派生出來的子進程。那個線程存在了三百多年,派生了幾千個子進程,這些子進程分布在世界的各個角落,構成了你們所說的‘魔法體系’?,F在父線程死了,子進程全部變成了孤兒進程,被init進程收養。但問題在于,這些孤兒進程里有很大一部分已經處于D狀態——不可中斷的睡眠,也就是——”皮克頓了頓,“僵尸化的前期。”。不可中斷的睡眠,通常發生在進程等待I/O操作的時候。正常情況下,操作系統會在一段時間后強制中斷,但在某些*uggy的內核版本里,進程會永遠卡在D狀態,連SIGKILL都殺不死。唯一的方法是重啟整個系統。而在這里,重啟意味著回滾一百二十七年。“所以我們要做的,”周逸凡環顧四周,“是把這些D狀態的進程從等待隊列里拽出來,手動給它們喂一個I/O完成的信號,讓它們繼續往下跑?!?br>皮克用那對大得離譜的眼睛盯著他:“你真的是程序員?不是路邊撿的?”
“我是被裁員的前高級工程師,不是被系統踢出來的實習生?!?br>“行,”皮克從工裝褲口袋里掏出一個比它拳頭還大的平板電腦——周逸凡不知道它那點大的口袋是怎么裝下這個東西的——然后啪地一下把平板展開,上面顯示著一張密密麻麻的地圖,“這里是斯維爾魔法學院,整個**排名第三的魔法教育機構。它在**gic_overflow線程里注冊了大約兩百三十個魔法進程,涉及的元素魔法、變形術、預言系等等。現在所有進程全部卡在D狀態,原因統一是:等待父線程返回一個魔法值?!?br>“什么魔法值?”
“不知道。那個值只有父線程知道,父線程已經死了,所以所有子進程都在等一個永遠不會來的返回值?!?br>周逸凡想了想。在編程里,這種情況有一個經典的解決方案:用默認值代替缺失的返回值。但默認值不能隨便選,必須滿足兩個條件——第一,不能破壞下游進程的輸入假設;第二,不能引發新的異常。
“我們需要找到每一個等待中的魔法進程,弄清楚它在等什么類型的返回值,然后給它一個合理的默認值?!?br>皮克看了看平板上的地圖:“兩百三十個進程,分布在整個學院的各個角落。我們得挨個找?!?br>“分開找?”
“分開找死得更快,”皮克說,“你是root,只有你才有權限改內存值。我只是個運維,只能讀,不能寫。你要是不在我旁邊,我找到了也修不了。”
周逸凡嘆了口氣,朝著最近的一個凝固的人形生物走去。
那是一個尖耳朵的高個子,穿著深藍色的長袍,胸口別著一個銀色的徽章,上面刻著一只展翅的鷹。他的右手舉在半空中,食指指著前方,嘴唇微張,像是在念咒語。周逸凡靠近了才發現,他的指尖有一團極其微弱的光,像快要熄滅的打火機的火焰,不停地閃爍。
“這是在施法過程中被凍結的,”皮克跳上周逸凡的肩膀,湊過去看了看那團光,“他在調用一個火球術函數。你看到那團光了嗎?正常情況下它應該越變越大,最后脫離指尖飛出去。但現在因為父線程沒有返回值,它卡在了‘請求魔法值’這一步,永遠等不到燃料?!?br>“火球術需要什么返回值?”
“魔法量。通俗地說,就是這個火球應該有多大、多熱、飛多遠。這些參數由父線程的魔法溢出機制動態計算?,F在父線程死了,這個火球術進程就在等一個永遠不會傳來的參數包?!?br>周逸凡低頭看了看手機。屏幕上顯示著recovery>提示符,光標一閃一閃的,旁邊還有一行新出現的狀態欄:
[location]斯維爾魔法學院,主禮堂,坐標(0x7F3A, 0x2C4*)
[process]火球術調用 #127,PID=0341,state=D,waiting_for=**gic_value_pack
[action required]
他需要給這個進程喂一個魔法值包。但他不知道正常的魔法值應該是什么。隨便給一個數,可能會炸。
“皮克,正常情況下,一個火球術的魔法值包大概是什么量級?”
“因人而異,”皮克說,“魔法師的魔力上限不同,調用同一個函數,返回的參數也不同。這個施法者的魔力上限是多少——等等,我看一下?!彼谄桨迳蟿澚藥紫拢鞍瑺栁摹こ啃牵A火系魔法師,魔力上限大約在三千七百個單位左右。一個標準的火球術消耗三百到五百個單位,飛行速度取決于魔力壓縮比……”
“說人話。”
“給他四百個單位,壓縮比2:1,飛行距離三十米,爆炸半徑一米五。這是教科書標準值?!?br>周逸凡在手機上輸入:
set_process_param PID=0341 **gic_value_pack = {amount:400, compression:2.0, distance:30, *last_radius:1.5}
按下回車。
那團微弱的火光突然亮了起來,從暗**變成亮橙色,然后迅速膨脹到拳頭大小,從艾爾文的指尖脫離,無聲無息地飛了出去,撞在禮堂的墻壁上,砰的一聲炸開——聲音不大,像一個氣球爆了。墻上的彩繪玻璃震了一下,但沒碎。
周逸凡還沒來得及反應,艾爾文·晨星的眼睛眨了。
尖耳朵魔法師的瞳孔從渙散狀態迅速聚焦,他看到面前站著一個穿著沖鋒衣、背著雙肩包、手里舉著一部碎屏手機的普通人類男性,以及他肩膀上那只灰藍色的毛球。艾爾文的表情從困惑變成了警惕,又從警惕變成了震驚。
“你——”他的聲音沙啞,像是很久沒有說過話,“你解了我的法術鎖?”
“算是吧,”周逸凡說,“你現在感覺怎么樣?”
艾爾文低頭看了看自己的手,握了握拳,又松開。他渾身上下檢查了一遍,然后抬頭看著周逸凡,眼神里多了一種說不清道不明的東西:“你是誰?你怎么能繞過魔法樞密院的權限直接修改施法參數?這不可能,整個**只有大賢者才有這個能力,而大賢者已經——”
“死了?”皮克插嘴。
艾爾文這才注意到周逸凡肩膀上的皮克,他的表情從震驚變成了驚恐:“你是……你是系統運維?我在古籍上見過你們的畫像!你們是魔法誕生之前就存在的遠古生物!”
“第一,我不是生物,我是運維。第二,我不是遠古,我才八百多歲,在運維里還算年輕的。”皮克語氣平淡,“第三,別叫我遠古生物,叫我的名字,皮克?!?br>艾爾文看起來快要暈過去了。
周逸凡沒有時間安撫一個受了驚嚇的魔法師。他看了一眼手機,屏幕上已經彈出了新的提示:這個禮堂里還有三十七個等待中的進程,分布在不同的位置,凍結著不同的人。他需要一個個修。
“聽著,”周逸凡對艾爾文說,“你們學院現在所有魔法都被凍結了。我來修。你幫我一個忙:告訴我這里哪些人的魔法最重要,最緊急,優先修。哪些人可以往后放?!?br>艾爾文深吸了幾口氣,努力讓自己冷靜下來。他的職業素養終于戰勝了恐懼:“最緊急的是二樓的醫療翼。那里有十幾個重傷員,他們的治療術被凍結了,如果不盡快恢復,凍結**之后他們會立刻死去——因為治療術只進行到一半?!?br>周逸凡臉色變了。他只想到修進程,沒想到進程恢復之后,被暫停的副作用會立刻生效。一個被凍住的傷員,在凍結期間不會惡化,但如果治療術只恢復了一半,凍結**的那一瞬間,傷口會繼續流血,而治療術還沒有完成。
“走,”周逸凡說,“帶路?!?br>艾爾文轉身就跑,長袍的下擺在身后飄起來。周逸凡跟在他后面,皮克蹲在肩膀上,平板電腦還亮著地圖。他們穿過禮堂側門,進入一條長長的走廊。走廊兩邊的墻壁上也嵌著彩繪玻璃,上面的符文同樣在變淡。每隔幾米就有一個凝固的人——有的是端著托盤的仆人,有的是拿著書的學員,還有一個正從樓梯上摔下來的姿勢極其扭曲的胖老頭,懸浮在半空中,離地面還有兩級臺階。
“那是我們的煉金術教授,”艾爾文一邊跑一邊回頭看了一眼,“他每次下樓梯都會踩到自己的袍子,我們都習慣了。”
周逸凡沒忍住笑了一聲,但很快收了回去。
醫療翼在二樓東側,是一個半圓形的房間,里面擺著二十多張床。大部分床上都躺著人,有的纏著繃帶,有的身上插著各種管子——不是輸液管,而是透明的、里面流動著發光液體的軟管。最靠近門口的一張床上,躺著一個年輕的女性,她的左臂從肘部以下被什么東西整齊地切掉了,傷口處有一層淡藍色的薄膜覆蓋著,膜下面是正在緩慢生長的骨骼和肌肉。
“她的手臂被魔化獸咬斷了,”艾爾文說,“治療師用再生術幫她重鑄骨骼和肌肉。再生術需要持續注入魔法值一百七十個單位每分鐘,現在已經中斷了——按凍結時間算,大概中斷了相當于現實時間的二十幾分鐘。”
“凍結時間是多少?”周逸凡問皮克。
“空洞內部的凍結時間是絕對的,”皮克說,“也就是說,這些進程在空洞被隔離的那一刻就全部暫停了,外部世界的任何變化都不會影響它們。但從他們的視角看,從暫停到恢復只是眨眼之間?!?br>“所以他們不知道自己被凍住了?”
“不知道。對他們來說,上一秒你還在修火球術,下一秒你就出現在醫療翼,中間沒有任何時間流逝。”
周逸凡松了一口氣。至少他不需要解釋“你們被凍結在系統底層”這種讓人崩潰的事情。
他走到那個斷臂女孩的床前,看了一眼手機。屏幕上顯示:
[process]再生術 #44,PID=0712,state=D,waiting_for=**gic_value_continuous
連續魔法值注入。這不是一次性給一個值就能解決的,需要建立一個持續的供給通道。周逸凡從來沒有在命令行里做過這種事。
“皮克,持續注入怎么搞?”
皮克從口袋里掏出一個比它手指還小的U盤——周逸凡不知道它到底有多少口袋——**了平板的接口。平板上彈出一個界面,看起來像是一個精簡版的進程管理器。
“你需要創建一個魔法值管道,把父線程的職責接管過來,”皮克說,“你現在是root,你可以模擬父線程的行為。也就是說,你要以每分鐘一百七十個單位的速度,持續不斷地向這個再生術進程推送魔法值,直到它完成。”
“手動推送?我每分鐘敲一次回車?”
“當然不是手動,你可以寫一個腳本?!?br>周逸凡愣住了。他在系統底層,在一個由內存地址和進程構成的世界里,寫腳本?
他低頭看了看手機。屏幕上出現了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.
床邊的軟**,發光液體重新開始流動。斷臂女孩傷口上的藍色薄膜變亮了一些,里面的骨骼和肌肉以肉眼可見的速度生長了一小截。她的眉頭微微皺了一下,像是在做夢。
周逸凡沒有停下來欣賞。他轉身看向艾爾文:“下一個?!?br>艾爾文已經從一個驚恐的魔法師變成了一個高效的導診員。他用最快的速度在醫療翼里跑了一圈,在每一張床前停了不到兩秒鐘,然后回到周逸凡面前,喘著氣說:“優先級從高到低:三號床,心臟衰竭,需要魔法起搏器持續輸出;七號床,中毒,需要解毒術每三十秒刷新一次參數;十一號床,靈魂損傷,需要——”
“等等,”周逸凡打斷他,“靈魂損傷是什么?”
“字面意思,”皮克說,“靈魂被撕裂了一部分。需要用一個錨定術把它重新固定回身體。錨定術需要的魔法值不是固定值,而是根據靈魂碎片的大小動態調整。你需要寫一個自適應腳本,每十秒鐘讀取一次碎片大小,然后調整注入量?!?br>周逸凡看著手機屏幕,沉默了三秒鐘。他想起自己以前寫過一個自適應限流器,根據系統的實時負載動態調整請求的閾值。那個限流器上線之后,系統穩定性提升了百分之四十,然后他被裁員了。
“寫就寫,”他說,手指開始在屏幕上飛舞。
接下來大約一個小時——如果時間在這個空洞里還有意義的話——周逸凡在醫療翼里一個床位一個床位地修。他寫了六個不同的腳本,處理了三種不同的持續注入模式,給十七個不同的進程喂了默認值。手機屏幕上的命令歷史已經滾了好幾屏,他的手指開始發酸,眼睛也開始干澀。
但他沒有停。
皮克在旁邊當他的活文檔,隨時告訴他每個魔法的標準參數范圍、每個魔法師的魔力上限、每個治療術的正常進度。艾爾文負責跑腿,把周逸凡從一個床位帶到另一個床位,順便在他每次修好一個人之后說一句“修好了”。
到第十七個傷員恢復的時候,周逸凡終于直起腰,轉了轉脖子,頸椎發出咔咔的聲音。他看了看手機上的進度條:醫療翼完成度100%,整個斯維爾魔法學院完成度——12%。
十二個百分比。兩百三十個進程,他修了十七個。
“還有兩百一十三個,”皮克報數。
周逸凡閉上眼睛。他想起自己被裁員的那天下午,總監在會上說“公司正在進行結構性優化”,翻譯過來就是“你不夠便宜了”?,F在他想對老天爺說同一句話:你們這個系統的結構性也太**不優化了,到處都是坑,一個僵尸線程養了三百年,派生了兩百多個子進程,文檔沒有,注釋沒有,變量名還**是魔法的——你憑什么不崩?
但他說出口的是:“走吧,下一個地方是哪兒?”
“變形術教室,”艾爾文說,“三樓。那里有****學生被凍住了,他們正在上實踐課?!?br>“什么實踐課?”
“把自己變成動物。”
周逸凡想了想****半人半動物的學生被凍住的畫面,決定不去想。
他跟著艾爾文走出醫療翼,沿著樓梯上到三樓。變形術教室是一間很大的階梯教室,***站著一個頭發花白的老**,舉著魔杖,姿勢像在指揮交響樂。階梯座位上坐著四十六個學生——至少從座位數量上看應該是四十六個。但實際坐在座位上的,有四十三個人類、兩只貓、一條狗、一個看起來像貓頭鷹但體型跟人一樣大的東西,以及一坨周逸凡完全無法辨認形狀的灰色物質。
“那個是漢斯,”艾爾文指了指那坨灰色物質,“他每次變形都會出問題。上次他把自己的頭和腳的位置搞反了,上上次他把皮膚變成了鱗片但忘了改變骨骼結構,結果整個人變成了一條沒有骨頭的蛇。這次看起來像是把自己變成了一團不確定狀態的物質?!?br>“薛定諤的漢斯,”周逸凡說。
“誰?”
“一個物理學家,不是,不重要?!?br>周逸凡走到***,看了一眼老**。她的魔杖頂端有一顆亮藍色的寶石,寶石里封著一個正在旋轉的符文。他手機屏幕上顯示:
[process]群體變形術,PID=0891,state=D,waiting_for=**gic_value_**trix
魔法值矩陣。這不是一個單一的值,而是一個四十六行乘五列的矩陣,每一行對應一個學生,每一列對應一個變形參數:目標形態、變形速度、保持時間、可逆性、副作用容忍度。
這個僵尸線程在死之前,正在批量處理四十六個學生的變形請求。它已經讀完了所有人的參數,正準備把計算結果寫回每個學生的進程。然后它死了。所有子進程都在等一個永遠不會來的結果矩陣。
周逸凡需要自己算出這個矩陣。
“皮克,”他說,“變形術的數學原理是什么?”
“每個學生的目標形態決定了變形公式,”皮克把平板上的數據投影到空中,形成一個半透明的三維圖表,“人變貓,需要壓縮骨骼、改變毛發密度、調整視網膜結構、重組內耳平衡系統。這些都需要精確的魔法值映射?!?br>“有計算公式嗎?”
“有,”皮克說,“但公式里的常數只有父線程知道。父線程死了,常數丟失了。”
周逸凡盯著空中那些密密麻麻的公式和參數,腦子里飛速運轉。他想起自己在上一家公司寫過一個機器學習模型,用來預測用戶行為。那個模型有十七個特征、四個隱藏層、兩百多個參數。他在沒有文檔的情況下接手了這個模型,花了三個月反向推導出了所有參數的意義。
三個月。他沒有三個月。他只有現在。
“我要用逆向工程,”周逸凡說,“從每個學生當前的狀態反推出變形公式的常數?!?br>“怎么反推?”
“你看這個學生,”周逸凡走到一個正在變成貓的學生面前,那學生已經長出了貓耳朵和胡須,但身體還是人類的,“他已經完成了變形的一部分。骨骼壓縮了百分之四十,毛發密度增加了百分之六十,視網膜還沒有開始調整。這說明父線程在處理他的請求時,是按照一定順序執行的:先骨骼,再毛發,再感官。每一步的魔法值比例,可以推算出常數?!?br>皮克眨了眨眼睛:“你確定?”
“不確定,”周逸凡說,“但總比什么都不做強?!?br>他蹲下來,開始觀察每一個變形中的學生,記錄數據,在手機上建立一個簡單的數學模型,求解常數。他花了大約四十分鐘,算了三遍,得出了四組可能的常數。他選了其中一組,代入了變形公式,算出了四十六行五列的矩陣。
然后他把矩陣寫進了手機:
set_process_param PID=0891 **gic_value_**trix = [46x5 **trix **ta]
按下回車。
教室里的空氣突然震動了一下。***的老**手中的魔杖頂端爆出一團亮光,然后那顆藍色寶石像心臟一樣開始跳動。四十六個學生的身體同時發生變化——貓的耳朵縮了回去,狗的尾巴長了出來,那坨灰色物質開始像橡皮泥一樣自我塑造,逐漸顯現出一個人形。
漢斯變成了一個瘦高的金發男孩,一臉茫然地看了看自己的手,然后看了看周逸凡,張嘴說了一句話:“我是不是又變形失敗了?”
“沒有,”艾爾文搶在周逸凡前面說,“你成功了。你變成——你變成了你自己。這是你今年第一次成功?!?br>漢斯愣了一下,然后激動地從座位上跳了起來,差點摔了一跤,扶住旁邊的同學才站穩。整個教室沸騰了,雖然其他學生還不完全清楚發生了什么,但看到漢斯終于從灰色物質變回了人形,所有人都自發地鼓起了掌。
周逸凡站在講臺旁邊,看著這群歡呼的年輕人,心里涌起一種奇怪的感覺。他在公司寫代碼的時候,從來沒有見過用戶為他的代碼鼓掌。用戶只會在他代碼出*ug的時候罵人,在他代碼不出*ug的時候當他不存在。而現在,在這個由內存地址和進程構成的荒謬世界里,一群被凍住的魔法學生,正在為恢復正常而歡呼。
他們不知道是他修的。他們甚至不知道他們曾經被凍住過。但沒關系。
“繼續,”周逸凡對艾爾文說,“下一個地方。”
變形術教室之后是預言系塔樓,然后是魔藥儲藏室,然后是飛行訓練場,然后是魔法生物飼養區。周逸凡從第一個空洞的這頭走到那頭,在每一個凍結的場景前停下來,讀代碼、猜參數、寫腳本、喂值。他的手機從滿電用到了百分之十二的電量,手指在碎屏上劃了好幾個小口子,沖鋒衣的袖口磨出了毛邊。
皮克在他肩膀上打了好幾次盹,醒來之后繼續報參數。艾爾文從一開始的驚恐變成了佩服,又從佩服變成了理所當然,開始用“那個修魔法的家伙”來稱呼周逸凡。
到第二百二十九個進程的時候,周逸凡已經連續工作了將近十個小時——如果時間真的在流逝的話。他的眼睛里全是血絲,腦子里塞滿了各種各樣的魔法參數、進程PID、注入腳本。他站在斯維爾魔法學院的圖書館里,面前是一個凍住的古籍修復師,她正在修復一本***前的古書,書頁上的文字正在從模糊變清晰的過程中被凍住了。
[process]古籍修復術,PID=1123,state=D,waiting_for=**gic_value_preservation_pack
這是倒數第二個。最后一個在圖書館的頂層——一個正在召喚元素精靈的召喚陣,那個進程需要的不是魔法值,而是一個精靈契約的簽名。周逸凡已經讓皮克查了標準契約模板,準備最后一起修。
他輸入了古籍修復術需要的參數,按下回車。修復師的眼睛眨了一下,她低頭看了看手里的書,又看了看周逸凡,禮貌地點了點頭,繼續工作。
周逸凡轉身走向樓梯,準備去頂層修最后一個。
然后他聽到了一個聲音。
不是從手機里傳出來的,不是皮克的聲音,也不是艾爾文的聲音。那個聲音來自四面八方,像從墻壁里、從地板下、從天花板上同時傳來,低沉、緩慢,每一個字都像敲在骨頭上:
“你是***?”
周逸凡停下腳步。
“你是***,”那個聲音重復了一遍,這次是陳述句,不是疑問句,“你是這個世界一直在等的***。”
“誰在說話?”周逸凡握緊了手機。
“我,”那個聲音說,“是你在修的最后一個進程?!?br>周逸凡愣住了。最后一個進程是一個召喚陣,它在召喚什么東西?
“你不用害怕,”那個聲音說,語氣平靜得像在念課文,“我不是什么**或神靈。我是這個世界的一個組成部分,就像重力、光、時間一樣。我只是很久沒有被人召喚過了,久到連我自己都忘了自己叫什么名字。”
“那你是什么?”周逸凡問。
“我是‘注釋’,”那個聲音說,“這個世界上每一行代碼旁邊的注釋。你們在源代碼里寫下的那些說明文字,那些被刪掉也不會影響運行的文字,那些被所有人忽略但只有讀代碼的人才會認真看的東西。我就是那個東西的具象化?!?br>“注釋能說話?”
“注釋不能說話,”那個聲音說,“但你能聽見我說話,因為你現在是root。只有root能聽見注釋?!?br>周逸凡想起自己在手機里寫的那條簽名——那行被他當作注釋寫進系統的字:“寫了一輩子屎山代碼,最后被老天爺當補丁用了。”
如果他寫的注釋能被系統聽見,那系統里原本就存在的注釋,是不是也在一直說話,只是從來沒有人聽見?
“你找我干什么?”周逸凡問。
“不是我找你,”注釋說,“是你召喚了我。你用那些逆向工程、那些默認值、那些腳本,把我從系統的縫隙里拽了出來。因為你在做一件只有注釋才能幫忙的事——你在理解這個沒有文檔的系統?!?br>“你能幫我?”
“我能告訴你這個系統的設計初衷,”注釋說,“我能告訴你那些丟失的常數原來是什么,那些僵尸線程為什么要被創造出來,那些魔法值矩陣的原始公式是什么。我能告訴你一切——只要你把我從召喚陣里放出來?!?br>周逸凡走上樓梯,推開頂層的一扇木門,看到了那個召喚陣。
這是一個用銀色線條畫在地上的六芒星,每一個角上放著一顆不同顏色的寶石。六芒星的正中央,懸浮著一團沒有固定形狀的光,像一團被揉皺的星云。那就是注釋。
“放你出來需要什么條件?”周逸凡問。
“很簡單,”注釋說,“把召喚陣的最后一個參數補全。那個參數原本應該是一個靈魂印記,用來綁定召喚者和被召喚者之間的契約。父線程死了,這個靈魂印記就丟失了。你可以用自己的靈魂印記代替?!?br>“用我的靈魂?聽起來不像一個簡單的事情。”
“很簡單,”注釋說,“你只需要在手機上輸入一行命令:**nd_soul PID=1133 with_current_user。按回車,我就出來了。然后我可以幫你修好這個世界剩下的所有空洞——不只是這一個,而是整個系統里成百上千個空洞。我一個注釋就能搞定?!?br>周逸凡低頭看著手機屏幕。確實,help命令里有一條**nd_soul,說明文檔寫的是“將當前用戶與指定進程綁定,建立永久性契約”。
他正要輸入,皮克突然在他肩膀上狠狠地揪了他耳朵一下。
“別信它,”皮克的聲音又尖又急,“注釋是系統里最危險的東西。它看起來什么都知道,但它只會告訴你它想讓你知道的事情。而且——一個靈魂印記只能綁定一次,綁定了就不能解綁。你綁了它,你就永遠跟它連在一起了,你死了它都不會放手。你知道這意味著什么嗎?”
“意味著什么?”
“意味著你會變成注釋的一部分,”皮克說,“你不是在召喚它,你是在把自己獻給它。”
注釋的聲音再次響起,這次帶著一絲笑意:“皮克,你還是這么不信任我。***了,你做了***運維,你什么時候見我害過***?”
“你沒害過***是因為*****本沒有***!”皮克吼道,“你是注釋,你生來就是為了被忽略的!現在突然來了一個root,你就想把自己綁上去——你這不是害人是什么?”
周逸凡站在召喚陣前,手機屏幕上的光標一閃一閃的,等著他輸入命令。他的手指懸在屏幕上方,離那行命令只有一厘米的距離。
他看了看注釋——那團被揉皺的星云,安靜地懸浮在六芒星中央,發出柔和的光。他又看了看皮克——那只灰藍色的小東西,正瞪大了眼睛看著他,瞳孔縮成了一條豎線,耳朵緊緊地貼在腦袋上,像一只炸了毛的貓。
“我先不綁定,”周逸凡說,“我先把這個學院修完。最后一個進程——就是這個召喚陣——我用默認參數把它完成,把你放出來,但不綁定靈魂。你愿意嗎?”
注釋沉默了三秒鐘。
“行,”它說,“用默認參數也行。但默認參數只能維持三十天。三十天之后,契約失效,我會重新被封印回召喚陣。到時候你如果不來續約,我就永遠出不來了。”
“三十天夠了,”周逸凡說,“三十天之內我會回來的?!?br>他輸入了默認參數,按下回車。
六芒星亮了起來,每一顆寶石都射出一道光線,匯聚到中央的星云上。星云開始旋轉,越轉越快,最后像一個漩渦一樣收縮、凝聚、變成了一顆豌豆大小的銀色珠子,落在地上,滾了兩圈,停在了周逸凡的鞋尖前面。
皮克從肩膀上跳下來,用兩根手指捏起那顆珠子,舉到眼前看了看,然后塞進了工裝褲的口袋里。
“我幫你保管,”皮克說,“你不能碰它,至少在三十天內不能?!?br>周逸凡沒有反對。
他看了看手機,斯維爾魔法學院的進度條終于走到了100%。屏幕上彈出了一行綠色的字:
[system]斯維爾魔法學院恢復完成。所有進程已修復??斩凑谑湛s。
周圍的空氣開始震動,圖書館的墻壁變得透明,像冰塊在融化。他透過墻壁看到了外面的走廊、樓梯、禮堂,然后看到了更外面的灰色虛空。整個空洞像一個肥皂泡一樣在收縮,把他和皮克、艾爾文、以及所有他修復過的人,一起吐了出來。
他們回到了那個發光的走廊。
艾爾文站在走廊里,茫然地看著四周:“這是哪兒?”
“不重要,”周逸凡說,“你回去吧。你的學院已經恢復正常了?!?br>艾爾文張了張嘴,想說什么,但沒說出來。他深深地看了周逸凡一眼,然后像被什么東西吸走了一樣,嗖地消失了。
皮克蹲在周逸凡肩膀上,看著手機屏幕上的新消息:
[system]空洞#1已關閉。剩余空洞數量:無法計數。建議先吃頓飯。
“它建議你吃飯,”皮克說。
周逸凡摸了摸肚子,這才發現自己已經餓得前胸貼后背了。他從雙肩包里掏出一個被壓扁了的面包——還是昨天從公司帶出來的,已經硬得像磚頭。他掰了一塊塞進嘴里,嚼了嚼,咽了下去。
“不好吃,”他說。
“在系統底層你還能指望什么?”皮克說,“不過我可以告訴你一個好消息?!?br>“什么?”
“第一個空洞是最難的。后面的空洞,難度會逐級降低。因為你每修一個空洞,就會多積累一點經驗,也會多獲得一點系統權限。等你修到第十個空洞的時候,你可能已經能用語音控制手機了。等你修到第五十個的時候,你可能揮揮手就能修好一個進程?!?br>“那我修完所有空洞之后呢?”
皮克看了他一眼,耳朵抖了一下:“你真想知道?”
“說?!?br>“修完所有空洞之后,你會成為這個世界的新內核,”皮克說,“不是***,不是root,而是內核本身。你會取代那個已經死了三百多年的父線程,成為所有魔法、所有進程、所有生命的底層邏輯。那時候你就不是‘在修系統’了,你就是系統。”
周逸凡又掰了一塊硬面包塞進嘴里,慢慢地嚼著。
“聽起來像一個比裁員更糟糕的工作,”他說。
皮克沒有回答,只是從他肩膀上跳下來,沿著發光的走廊往前走了幾步,然后回頭看他:“走吧,第二個空洞在東邊。大約三十分鐘路程。你可以邊走邊吃?!?br>周逸凡把剩下的面包塞回包里,跟上了皮克的腳步。
發光的走廊在他身后慢慢暗了下去,像一條剛剛走過的路,正在被黑暗吞沒。他不知道這條走廊有多長,不知道還有多少個空洞在等著他,不知道自己會不會在修完所有空洞之后真的變成那個所謂的內核。
但他知道一件事:他現在有一份工作,一份不會裁員的工作,一份如果他不干整個世界就會崩潰的工作。
諷刺。
“我是被裁員的前高級工程師,不是被系統踢出來的實習生?!?br>“行,”皮克從工裝褲口袋里掏出一個比它拳頭還大的平板電腦——周逸凡不知道它那點大的口袋是怎么裝下這個東西的——然后啪地一下把平板展開,上面顯示著一張密密麻麻的地圖,“這里是斯維爾魔法學院,整個**排名第三的魔法教育機構。它在**gic_overflow線程里注冊了大約兩百三十個魔法進程,涉及的元素魔法、變形術、預言系等等。現在所有進程全部卡在D狀態,原因統一是:等待父線程返回一個魔法值?!?br>“什么魔法值?”
“不知道。那個值只有父線程知道,父線程已經死了,所以所有子進程都在等一個永遠不會來的返回值?!?br>周逸凡想了想。在編程里,這種情況有一個經典的解決方案:用默認值代替缺失的返回值。但默認值不能隨便選,必須滿足兩個條件——第一,不能破壞下游進程的輸入假設;第二,不能引發新的異常。
“我們需要找到每一個等待中的魔法進程,弄清楚它在等什么類型的返回值,然后給它一個合理的默認值?!?br>皮克看了看平板上的地圖:“兩百三十個進程,分布在整個學院的各個角落。我們得挨個找?!?br>“分開找?”
“分開找死得更快,”皮克說,“你是root,只有你才有權限改內存值。我只是個運維,只能讀,不能寫。你要是不在我旁邊,我找到了也修不了。”
周逸凡嘆了口氣,朝著最近的一個凝固的人形生物走去。
那是一個尖耳朵的高個子,穿著深藍色的長袍,胸口別著一個銀色的徽章,上面刻著一只展翅的鷹。他的右手舉在半空中,食指指著前方,嘴唇微張,像是在念咒語。周逸凡靠近了才發現,他的指尖有一團極其微弱的光,像快要熄滅的打火機的火焰,不停地閃爍。
“這是在施法過程中被凍結的,”皮克跳上周逸凡的肩膀,湊過去看了看那團光,“他在調用一個火球術函數。你看到那團光了嗎?正常情況下它應該越變越大,最后脫離指尖飛出去。但現在因為父線程沒有返回值,它卡在了‘請求魔法值’這一步,永遠等不到燃料?!?br>“火球術需要什么返回值?”
“魔法量。通俗地說,就是這個火球應該有多大、多熱、飛多遠。這些參數由父線程的魔法溢出機制動態計算?,F在父線程死了,這個火球術進程就在等一個永遠不會傳來的參數包?!?br>周逸凡低頭看了看手機。屏幕上顯示著recovery>提示符,光標一閃一閃的,旁邊還有一行新出現的狀態欄:
[location]斯維爾魔法學院,主禮堂,坐標(0x7F3A, 0x2C4*)
[process]火球術調用 #127,PID=0341,state=D,waiting_for=**gic_value_pack
[action required]
他需要給這個進程喂一個魔法值包。但他不知道正常的魔法值應該是什么。隨便給一個數,可能會炸。
“皮克,正常情況下,一個火球術的魔法值包大概是什么量級?”
“因人而異,”皮克說,“魔法師的魔力上限不同,調用同一個函數,返回的參數也不同。這個施法者的魔力上限是多少——等等,我看一下?!彼谄桨迳蟿澚藥紫拢鞍瑺栁摹こ啃牵A火系魔法師,魔力上限大約在三千七百個單位左右。一個標準的火球術消耗三百到五百個單位,飛行速度取決于魔力壓縮比……”
“說人話。”
“給他四百個單位,壓縮比2:1,飛行距離三十米,爆炸半徑一米五。這是教科書標準值?!?br>周逸凡在手機上輸入:
set_process_param PID=0341 **gic_value_pack = {amount:400, compression:2.0, distance:30, *last_radius:1.5}
按下回車。
那團微弱的火光突然亮了起來,從暗**變成亮橙色,然后迅速膨脹到拳頭大小,從艾爾文的指尖脫離,無聲無息地飛了出去,撞在禮堂的墻壁上,砰的一聲炸開——聲音不大,像一個氣球爆了。墻上的彩繪玻璃震了一下,但沒碎。
周逸凡還沒來得及反應,艾爾文·晨星的眼睛眨了。
尖耳朵魔法師的瞳孔從渙散狀態迅速聚焦,他看到面前站著一個穿著沖鋒衣、背著雙肩包、手里舉著一部碎屏手機的普通人類男性,以及他肩膀上那只灰藍色的毛球。艾爾文的表情從困惑變成了警惕,又從警惕變成了震驚。
“你——”他的聲音沙啞,像是很久沒有說過話,“你解了我的法術鎖?”
“算是吧,”周逸凡說,“你現在感覺怎么樣?”
艾爾文低頭看了看自己的手,握了握拳,又松開。他渾身上下檢查了一遍,然后抬頭看著周逸凡,眼神里多了一種說不清道不明的東西:“你是誰?你怎么能繞過魔法樞密院的權限直接修改施法參數?這不可能,整個**只有大賢者才有這個能力,而大賢者已經——”
“死了?”皮克插嘴。
艾爾文這才注意到周逸凡肩膀上的皮克,他的表情從震驚變成了驚恐:“你是……你是系統運維?我在古籍上見過你們的畫像!你們是魔法誕生之前就存在的遠古生物!”
“第一,我不是生物,我是運維。第二,我不是遠古,我才八百多歲,在運維里還算年輕的。”皮克語氣平淡,“第三,別叫我遠古生物,叫我的名字,皮克?!?br>艾爾文看起來快要暈過去了。
周逸凡沒有時間安撫一個受了驚嚇的魔法師。他看了一眼手機,屏幕上已經彈出了新的提示:這個禮堂里還有三十七個等待中的進程,分布在不同的位置,凍結著不同的人。他需要一個個修。
“聽著,”周逸凡對艾爾文說,“你們學院現在所有魔法都被凍結了。我來修。你幫我一個忙:告訴我這里哪些人的魔法最重要,最緊急,優先修。哪些人可以往后放?!?br>艾爾文深吸了幾口氣,努力讓自己冷靜下來。他的職業素養終于戰勝了恐懼:“最緊急的是二樓的醫療翼。那里有十幾個重傷員,他們的治療術被凍結了,如果不盡快恢復,凍結**之后他們會立刻死去——因為治療術只進行到一半?!?br>周逸凡臉色變了。他只想到修進程,沒想到進程恢復之后,被暫停的副作用會立刻生效。一個被凍住的傷員,在凍結期間不會惡化,但如果治療術只恢復了一半,凍結**的那一瞬間,傷口會繼續流血,而治療術還沒有完成。
“走,”周逸凡說,“帶路?!?br>艾爾文轉身就跑,長袍的下擺在身后飄起來。周逸凡跟在他后面,皮克蹲在肩膀上,平板電腦還亮著地圖。他們穿過禮堂側門,進入一條長長的走廊。走廊兩邊的墻壁上也嵌著彩繪玻璃,上面的符文同樣在變淡。每隔幾米就有一個凝固的人——有的是端著托盤的仆人,有的是拿著書的學員,還有一個正從樓梯上摔下來的姿勢極其扭曲的胖老頭,懸浮在半空中,離地面還有兩級臺階。
“那是我們的煉金術教授,”艾爾文一邊跑一邊回頭看了一眼,“他每次下樓梯都會踩到自己的袍子,我們都習慣了。”
周逸凡沒忍住笑了一聲,但很快收了回去。
醫療翼在二樓東側,是一個半圓形的房間,里面擺著二十多張床。大部分床上都躺著人,有的纏著繃帶,有的身上插著各種管子——不是輸液管,而是透明的、里面流動著發光液體的軟管。最靠近門口的一張床上,躺著一個年輕的女性,她的左臂從肘部以下被什么東西整齊地切掉了,傷口處有一層淡藍色的薄膜覆蓋著,膜下面是正在緩慢生長的骨骼和肌肉。
“她的手臂被魔化獸咬斷了,”艾爾文說,“治療師用再生術幫她重鑄骨骼和肌肉。再生術需要持續注入魔法值一百七十個單位每分鐘,現在已經中斷了——按凍結時間算,大概中斷了相當于現實時間的二十幾分鐘。”
“凍結時間是多少?”周逸凡問皮克。
“空洞內部的凍結時間是絕對的,”皮克說,“也就是說,這些進程在空洞被隔離的那一刻就全部暫停了,外部世界的任何變化都不會影響它們。但從他們的視角看,從暫停到恢復只是眨眼之間?!?br>“所以他們不知道自己被凍住了?”
“不知道。對他們來說,上一秒你還在修火球術,下一秒你就出現在醫療翼,中間沒有任何時間流逝。”
周逸凡松了一口氣。至少他不需要解釋“你們被凍結在系統底層”這種讓人崩潰的事情。
他走到那個斷臂女孩的床前,看了一眼手機。屏幕上顯示:
[process]再生術 #44,PID=0712,state=D,waiting_for=**gic_value_continuous
連續魔法值注入。這不是一次性給一個值就能解決的,需要建立一個持續的供給通道。周逸凡從來沒有在命令行里做過這種事。
“皮克,持續注入怎么搞?”
皮克從口袋里掏出一個比它手指還小的U盤——周逸凡不知道它到底有多少口袋——**了平板的接口。平板上彈出一個界面,看起來像是一個精簡版的進程管理器。
“你需要創建一個魔法值管道,把父線程的職責接管過來,”皮克說,“你現在是root,你可以模擬父線程的行為。也就是說,你要以每分鐘一百七十個單位的速度,持續不斷地向這個再生術進程推送魔法值,直到它完成。”
“手動推送?我每分鐘敲一次回車?”
“當然不是手動,你可以寫一個腳本?!?br>周逸凡愣住了。他在系統底層,在一個由內存地址和進程構成的世界里,寫腳本?
他低頭看了看手機。屏幕上出現了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.
床邊的軟**,發光液體重新開始流動。斷臂女孩傷口上的藍色薄膜變亮了一些,里面的骨骼和肌肉以肉眼可見的速度生長了一小截。她的眉頭微微皺了一下,像是在做夢。
周逸凡沒有停下來欣賞。他轉身看向艾爾文:“下一個?!?br>艾爾文已經從一個驚恐的魔法師變成了一個高效的導診員。他用最快的速度在醫療翼里跑了一圈,在每一張床前停了不到兩秒鐘,然后回到周逸凡面前,喘著氣說:“優先級從高到低:三號床,心臟衰竭,需要魔法起搏器持續輸出;七號床,中毒,需要解毒術每三十秒刷新一次參數;十一號床,靈魂損傷,需要——”
“等等,”周逸凡打斷他,“靈魂損傷是什么?”
“字面意思,”皮克說,“靈魂被撕裂了一部分。需要用一個錨定術把它重新固定回身體。錨定術需要的魔法值不是固定值,而是根據靈魂碎片的大小動態調整。你需要寫一個自適應腳本,每十秒鐘讀取一次碎片大小,然后調整注入量?!?br>周逸凡看著手機屏幕,沉默了三秒鐘。他想起自己以前寫過一個自適應限流器,根據系統的實時負載動態調整請求的閾值。那個限流器上線之后,系統穩定性提升了百分之四十,然后他被裁員了。
“寫就寫,”他說,手指開始在屏幕上飛舞。
接下來大約一個小時——如果時間在這個空洞里還有意義的話——周逸凡在醫療翼里一個床位一個床位地修。他寫了六個不同的腳本,處理了三種不同的持續注入模式,給十七個不同的進程喂了默認值。手機屏幕上的命令歷史已經滾了好幾屏,他的手指開始發酸,眼睛也開始干澀。
但他沒有停。
皮克在旁邊當他的活文檔,隨時告訴他每個魔法的標準參數范圍、每個魔法師的魔力上限、每個治療術的正常進度。艾爾文負責跑腿,把周逸凡從一個床位帶到另一個床位,順便在他每次修好一個人之后說一句“修好了”。
到第十七個傷員恢復的時候,周逸凡終于直起腰,轉了轉脖子,頸椎發出咔咔的聲音。他看了看手機上的進度條:醫療翼完成度100%,整個斯維爾魔法學院完成度——12%。
十二個百分比。兩百三十個進程,他修了十七個。
“還有兩百一十三個,”皮克報數。
周逸凡閉上眼睛。他想起自己被裁員的那天下午,總監在會上說“公司正在進行結構性優化”,翻譯過來就是“你不夠便宜了”?,F在他想對老天爺說同一句話:你們這個系統的結構性也太**不優化了,到處都是坑,一個僵尸線程養了三百年,派生了兩百多個子進程,文檔沒有,注釋沒有,變量名還**是魔法的——你憑什么不崩?
但他說出口的是:“走吧,下一個地方是哪兒?”
“變形術教室,”艾爾文說,“三樓。那里有****學生被凍住了,他們正在上實踐課?!?br>“什么實踐課?”
“把自己變成動物。”
周逸凡想了想****半人半動物的學生被凍住的畫面,決定不去想。
他跟著艾爾文走出醫療翼,沿著樓梯上到三樓。變形術教室是一間很大的階梯教室,***站著一個頭發花白的老**,舉著魔杖,姿勢像在指揮交響樂。階梯座位上坐著四十六個學生——至少從座位數量上看應該是四十六個。但實際坐在座位上的,有四十三個人類、兩只貓、一條狗、一個看起來像貓頭鷹但體型跟人一樣大的東西,以及一坨周逸凡完全無法辨認形狀的灰色物質。
“那個是漢斯,”艾爾文指了指那坨灰色物質,“他每次變形都會出問題。上次他把自己的頭和腳的位置搞反了,上上次他把皮膚變成了鱗片但忘了改變骨骼結構,結果整個人變成了一條沒有骨頭的蛇。這次看起來像是把自己變成了一團不確定狀態的物質?!?br>“薛定諤的漢斯,”周逸凡說。
“誰?”
“一個物理學家,不是,不重要?!?br>周逸凡走到***,看了一眼老**。她的魔杖頂端有一顆亮藍色的寶石,寶石里封著一個正在旋轉的符文。他手機屏幕上顯示:
[process]群體變形術,PID=0891,state=D,waiting_for=**gic_value_**trix
魔法值矩陣。這不是一個單一的值,而是一個四十六行乘五列的矩陣,每一行對應一個學生,每一列對應一個變形參數:目標形態、變形速度、保持時間、可逆性、副作用容忍度。
這個僵尸線程在死之前,正在批量處理四十六個學生的變形請求。它已經讀完了所有人的參數,正準備把計算結果寫回每個學生的進程。然后它死了。所有子進程都在等一個永遠不會來的結果矩陣。
周逸凡需要自己算出這個矩陣。
“皮克,”他說,“變形術的數學原理是什么?”
“每個學生的目標形態決定了變形公式,”皮克把平板上的數據投影到空中,形成一個半透明的三維圖表,“人變貓,需要壓縮骨骼、改變毛發密度、調整視網膜結構、重組內耳平衡系統。這些都需要精確的魔法值映射?!?br>“有計算公式嗎?”
“有,”皮克說,“但公式里的常數只有父線程知道。父線程死了,常數丟失了。”
周逸凡盯著空中那些密密麻麻的公式和參數,腦子里飛速運轉。他想起自己在上一家公司寫過一個機器學習模型,用來預測用戶行為。那個模型有十七個特征、四個隱藏層、兩百多個參數。他在沒有文檔的情況下接手了這個模型,花了三個月反向推導出了所有參數的意義。
三個月。他沒有三個月。他只有現在。
“我要用逆向工程,”周逸凡說,“從每個學生當前的狀態反推出變形公式的常數?!?br>“怎么反推?”
“你看這個學生,”周逸凡走到一個正在變成貓的學生面前,那學生已經長出了貓耳朵和胡須,但身體還是人類的,“他已經完成了變形的一部分。骨骼壓縮了百分之四十,毛發密度增加了百分之六十,視網膜還沒有開始調整。這說明父線程在處理他的請求時,是按照一定順序執行的:先骨骼,再毛發,再感官。每一步的魔法值比例,可以推算出常數?!?br>皮克眨了眨眼睛:“你確定?”
“不確定,”周逸凡說,“但總比什么都不做強?!?br>他蹲下來,開始觀察每一個變形中的學生,記錄數據,在手機上建立一個簡單的數學模型,求解常數。他花了大約四十分鐘,算了三遍,得出了四組可能的常數。他選了其中一組,代入了變形公式,算出了四十六行五列的矩陣。
然后他把矩陣寫進了手機:
set_process_param PID=0891 **gic_value_**trix = [46x5 **trix **ta]
按下回車。
教室里的空氣突然震動了一下。***的老**手中的魔杖頂端爆出一團亮光,然后那顆藍色寶石像心臟一樣開始跳動。四十六個學生的身體同時發生變化——貓的耳朵縮了回去,狗的尾巴長了出來,那坨灰色物質開始像橡皮泥一樣自我塑造,逐漸顯現出一個人形。
漢斯變成了一個瘦高的金發男孩,一臉茫然地看了看自己的手,然后看了看周逸凡,張嘴說了一句話:“我是不是又變形失敗了?”
“沒有,”艾爾文搶在周逸凡前面說,“你成功了。你變成——你變成了你自己。這是你今年第一次成功?!?br>漢斯愣了一下,然后激動地從座位上跳了起來,差點摔了一跤,扶住旁邊的同學才站穩。整個教室沸騰了,雖然其他學生還不完全清楚發生了什么,但看到漢斯終于從灰色物質變回了人形,所有人都自發地鼓起了掌。
周逸凡站在講臺旁邊,看著這群歡呼的年輕人,心里涌起一種奇怪的感覺。他在公司寫代碼的時候,從來沒有見過用戶為他的代碼鼓掌。用戶只會在他代碼出*ug的時候罵人,在他代碼不出*ug的時候當他不存在。而現在,在這個由內存地址和進程構成的荒謬世界里,一群被凍住的魔法學生,正在為恢復正常而歡呼。
他們不知道是他修的。他們甚至不知道他們曾經被凍住過。但沒關系。
“繼續,”周逸凡對艾爾文說,“下一個地方。”
變形術教室之后是預言系塔樓,然后是魔藥儲藏室,然后是飛行訓練場,然后是魔法生物飼養區。周逸凡從第一個空洞的這頭走到那頭,在每一個凍結的場景前停下來,讀代碼、猜參數、寫腳本、喂值。他的手機從滿電用到了百分之十二的電量,手指在碎屏上劃了好幾個小口子,沖鋒衣的袖口磨出了毛邊。
皮克在他肩膀上打了好幾次盹,醒來之后繼續報參數。艾爾文從一開始的驚恐變成了佩服,又從佩服變成了理所當然,開始用“那個修魔法的家伙”來稱呼周逸凡。
到第二百二十九個進程的時候,周逸凡已經連續工作了將近十個小時——如果時間真的在流逝的話。他的眼睛里全是血絲,腦子里塞滿了各種各樣的魔法參數、進程PID、注入腳本。他站在斯維爾魔法學院的圖書館里,面前是一個凍住的古籍修復師,她正在修復一本***前的古書,書頁上的文字正在從模糊變清晰的過程中被凍住了。
[process]古籍修復術,PID=1123,state=D,waiting_for=**gic_value_preservation_pack
這是倒數第二個。最后一個在圖書館的頂層——一個正在召喚元素精靈的召喚陣,那個進程需要的不是魔法值,而是一個精靈契約的簽名。周逸凡已經讓皮克查了標準契約模板,準備最后一起修。
他輸入了古籍修復術需要的參數,按下回車。修復師的眼睛眨了一下,她低頭看了看手里的書,又看了看周逸凡,禮貌地點了點頭,繼續工作。
周逸凡轉身走向樓梯,準備去頂層修最后一個。
然后他聽到了一個聲音。
不是從手機里傳出來的,不是皮克的聲音,也不是艾爾文的聲音。那個聲音來自四面八方,像從墻壁里、從地板下、從天花板上同時傳來,低沉、緩慢,每一個字都像敲在骨頭上:
“你是***?”
周逸凡停下腳步。
“你是***,”那個聲音重復了一遍,這次是陳述句,不是疑問句,“你是這個世界一直在等的***。”
“誰在說話?”周逸凡握緊了手機。
“我,”那個聲音說,“是你在修的最后一個進程?!?br>周逸凡愣住了。最后一個進程是一個召喚陣,它在召喚什么東西?
“你不用害怕,”那個聲音說,語氣平靜得像在念課文,“我不是什么**或神靈。我是這個世界的一個組成部分,就像重力、光、時間一樣。我只是很久沒有被人召喚過了,久到連我自己都忘了自己叫什么名字。”
“那你是什么?”周逸凡問。
“我是‘注釋’,”那個聲音說,“這個世界上每一行代碼旁邊的注釋。你們在源代碼里寫下的那些說明文字,那些被刪掉也不會影響運行的文字,那些被所有人忽略但只有讀代碼的人才會認真看的東西。我就是那個東西的具象化?!?br>“注釋能說話?”
“注釋不能說話,”那個聲音說,“但你能聽見我說話,因為你現在是root。只有root能聽見注釋?!?br>周逸凡想起自己在手機里寫的那條簽名——那行被他當作注釋寫進系統的字:“寫了一輩子屎山代碼,最后被老天爺當補丁用了。”
如果他寫的注釋能被系統聽見,那系統里原本就存在的注釋,是不是也在一直說話,只是從來沒有人聽見?
“你找我干什么?”周逸凡問。
“不是我找你,”注釋說,“是你召喚了我。你用那些逆向工程、那些默認值、那些腳本,把我從系統的縫隙里拽了出來。因為你在做一件只有注釋才能幫忙的事——你在理解這個沒有文檔的系統?!?br>“你能幫我?”
“我能告訴你這個系統的設計初衷,”注釋說,“我能告訴你那些丟失的常數原來是什么,那些僵尸線程為什么要被創造出來,那些魔法值矩陣的原始公式是什么。我能告訴你一切——只要你把我從召喚陣里放出來?!?br>周逸凡走上樓梯,推開頂層的一扇木門,看到了那個召喚陣。
這是一個用銀色線條畫在地上的六芒星,每一個角上放著一顆不同顏色的寶石。六芒星的正中央,懸浮著一團沒有固定形狀的光,像一團被揉皺的星云。那就是注釋。
“放你出來需要什么條件?”周逸凡問。
“很簡單,”注釋說,“把召喚陣的最后一個參數補全。那個參數原本應該是一個靈魂印記,用來綁定召喚者和被召喚者之間的契約。父線程死了,這個靈魂印記就丟失了。你可以用自己的靈魂印記代替?!?br>“用我的靈魂?聽起來不像一個簡單的事情。”
“很簡單,”注釋說,“你只需要在手機上輸入一行命令:**nd_soul PID=1133 with_current_user。按回車,我就出來了。然后我可以幫你修好這個世界剩下的所有空洞——不只是這一個,而是整個系統里成百上千個空洞。我一個注釋就能搞定?!?br>周逸凡低頭看著手機屏幕。確實,help命令里有一條**nd_soul,說明文檔寫的是“將當前用戶與指定進程綁定,建立永久性契約”。
他正要輸入,皮克突然在他肩膀上狠狠地揪了他耳朵一下。
“別信它,”皮克的聲音又尖又急,“注釋是系統里最危險的東西。它看起來什么都知道,但它只會告訴你它想讓你知道的事情。而且——一個靈魂印記只能綁定一次,綁定了就不能解綁。你綁了它,你就永遠跟它連在一起了,你死了它都不會放手。你知道這意味著什么嗎?”
“意味著什么?”
“意味著你會變成注釋的一部分,”皮克說,“你不是在召喚它,你是在把自己獻給它。”
注釋的聲音再次響起,這次帶著一絲笑意:“皮克,你還是這么不信任我。***了,你做了***運維,你什么時候見我害過***?”
“你沒害過***是因為*****本沒有***!”皮克吼道,“你是注釋,你生來就是為了被忽略的!現在突然來了一個root,你就想把自己綁上去——你這不是害人是什么?”
周逸凡站在召喚陣前,手機屏幕上的光標一閃一閃的,等著他輸入命令。他的手指懸在屏幕上方,離那行命令只有一厘米的距離。
他看了看注釋——那團被揉皺的星云,安靜地懸浮在六芒星中央,發出柔和的光。他又看了看皮克——那只灰藍色的小東西,正瞪大了眼睛看著他,瞳孔縮成了一條豎線,耳朵緊緊地貼在腦袋上,像一只炸了毛的貓。
“我先不綁定,”周逸凡說,“我先把這個學院修完。最后一個進程——就是這個召喚陣——我用默認參數把它完成,把你放出來,但不綁定靈魂。你愿意嗎?”
注釋沉默了三秒鐘。
“行,”它說,“用默認參數也行。但默認參數只能維持三十天。三十天之后,契約失效,我會重新被封印回召喚陣。到時候你如果不來續約,我就永遠出不來了。”
“三十天夠了,”周逸凡說,“三十天之內我會回來的?!?br>他輸入了默認參數,按下回車。
六芒星亮了起來,每一顆寶石都射出一道光線,匯聚到中央的星云上。星云開始旋轉,越轉越快,最后像一個漩渦一樣收縮、凝聚、變成了一顆豌豆大小的銀色珠子,落在地上,滾了兩圈,停在了周逸凡的鞋尖前面。
皮克從肩膀上跳下來,用兩根手指捏起那顆珠子,舉到眼前看了看,然后塞進了工裝褲的口袋里。
“我幫你保管,”皮克說,“你不能碰它,至少在三十天內不能?!?br>周逸凡沒有反對。
他看了看手機,斯維爾魔法學院的進度條終于走到了100%。屏幕上彈出了一行綠色的字:
[system]斯維爾魔法學院恢復完成。所有進程已修復??斩凑谑湛s。
周圍的空氣開始震動,圖書館的墻壁變得透明,像冰塊在融化。他透過墻壁看到了外面的走廊、樓梯、禮堂,然后看到了更外面的灰色虛空。整個空洞像一個肥皂泡一樣在收縮,把他和皮克、艾爾文、以及所有他修復過的人,一起吐了出來。
他們回到了那個發光的走廊。
艾爾文站在走廊里,茫然地看著四周:“這是哪兒?”
“不重要,”周逸凡說,“你回去吧。你的學院已經恢復正常了?!?br>艾爾文張了張嘴,想說什么,但沒說出來。他深深地看了周逸凡一眼,然后像被什么東西吸走了一樣,嗖地消失了。
皮克蹲在周逸凡肩膀上,看著手機屏幕上的新消息:
[system]空洞#1已關閉。剩余空洞數量:無法計數。建議先吃頓飯。
“它建議你吃飯,”皮克說。
周逸凡摸了摸肚子,這才發現自己已經餓得前胸貼后背了。他從雙肩包里掏出一個被壓扁了的面包——還是昨天從公司帶出來的,已經硬得像磚頭。他掰了一塊塞進嘴里,嚼了嚼,咽了下去。
“不好吃,”他說。
“在系統底層你還能指望什么?”皮克說,“不過我可以告訴你一個好消息?!?br>“什么?”
“第一個空洞是最難的。后面的空洞,難度會逐級降低。因為你每修一個空洞,就會多積累一點經驗,也會多獲得一點系統權限。等你修到第十個空洞的時候,你可能已經能用語音控制手機了。等你修到第五十個的時候,你可能揮揮手就能修好一個進程?!?br>“那我修完所有空洞之后呢?”
皮克看了他一眼,耳朵抖了一下:“你真想知道?”
“說?!?br>“修完所有空洞之后,你會成為這個世界的新內核,”皮克說,“不是***,不是root,而是內核本身。你會取代那個已經死了三百多年的父線程,成為所有魔法、所有進程、所有生命的底層邏輯。那時候你就不是‘在修系統’了,你就是系統。”
周逸凡又掰了一塊硬面包塞進嘴里,慢慢地嚼著。
“聽起來像一個比裁員更糟糕的工作,”他說。
皮克沒有回答,只是從他肩膀上跳下來,沿著發光的走廊往前走了幾步,然后回頭看他:“走吧,第二個空洞在東邊。大約三十分鐘路程。你可以邊走邊吃?!?br>周逸凡把剩下的面包塞回包里,跟上了皮克的腳步。
發光的走廊在他身后慢慢暗了下去,像一條剛剛走過的路,正在被黑暗吞沒。他不知道這條走廊有多長,不知道還有多少個空洞在等著他,不知道自己會不會在修完所有空洞之后真的變成那個所謂的內核。
但他知道一件事:他現在有一份工作,一份不會裁員的工作,一份如果他不干整個世界就會崩潰的工作。
諷刺。