你在一個 Python 後端工作了兩年。某天,你被拉去 debug 同事寫的 Go 服務。
第一個感覺是:完全不知道從哪裡開始。Goroutine 是什麼?err != nil 為什麼要一直重複?這個 chan 又是什麼東西?
一個月後,你學完基本 Go 語法,勉強能改 bug 了。但你還是有種感覺:你只是在記 Go 的「英文單字」,沒有真的搞懂它在說什麼。
這種感覺有個名字:語法會,模型不會。
語法是皮,模型是骨
Python 有 threading.Thread。Go 有 goroutine。JavaScript 有 async/await。Java 有 ExecutorService。
這四個東西的語法完全不同。但它們在解的是同一個問題:你有多件事情要同時處理,OS 只給你有限的 CPU,怎麼辦?
這個問題背後有一個模型:並行(concurrency)。理解了這個模型,你就知道為什麼 Go 的 goroutine 比 OS thread 便宜、為什麼 Node.js 能用單一 thread 應付大量請求、為什麼 Python 的 asyncio 和 threading 是兩件不同的事。
不理解這個模型,你只能記住「用 Go 要 go func()」,遇到問題時不知道發生了什麼。
跨語言共通概念,就是這些底層模型。
語法是表達方式,模型是被表達的東西。
五個不換的模型
換語言時,以下五個模型永遠都在,只是長相不同:
並行模型:這個語言用什麼機制讓多件事同時進行?OS thread?Coroutine?Event loop?Actor?
這個模型決定了你能撐多少並行連線、CPU 密集任務會不會把服務卡死、你需不需要手動寫鎖。Python 的 asyncio 和 threading 在語法上都算「並行」,但底層模型完全不同——搞不清楚這一點,你換 Node.js 或 Go 的時候同樣會栽。
記憶體模型:程式的記憶體誰負責收?Go 和 Java 有 GC,Rust 用 ownership,C/C++ 要手動。選擇不同,效能特性和可能的 bug 類型就不同。
型別系統:這個語言在哪個階段抓型別錯誤?編譯時還是執行時?型別是結構相符就好(TypeScript)還是名字要一樣(Java)?
IO 模型:讀一個檔案、打一個 API,這個「等待」是阻塞 thread 還是非阻塞?底層機制是 epoll 還是 io_uring?
錯誤處理模型:出錯時這個語言要你怎麼辦?Exception(Python、Java)?Result type(Rust)?return error value(Go)?每種選擇對程式碼結構的影響完全不同。
這五個模型,在任何後端語言裡都能找到對應的實作。知道模型在哪、長什麼樣,你就能快速定位新語言的對應位置,而不是從頭摸索。
和 framework 概念的關係
你可能已經讀過 backend/framework/generic/ 系列。那個系列講的是框架層的決策——為什麼選 Express 不選 Django、DI 怎麼用、middleware 怎麼串。
B01 這個系列在更底一層。
framework 說「FastAPI 用 async 函式,Django 用 sync 函式」。
B01 說「async 底層是 event loop,event loop 的原理是什麼、為什麼比 thread 省資源」。
framework 文章預設你知道「並行模型是什麼」。B01 補的就是這個前提。如果你已經讀過 framework 系列,B01 會讓那些選型決策變得更有根據;如果你從 B01 開始,再去讀 framework 系列,很多東西會突然通。
這個系列怎麼讀
B01 的文章分六組。前兩組(01–08)是背景——為什麼要懂這些、這些概念怎麼演進來的。第三組開始才是具體的模型解析:變數/記憶體、並行/IO、錯誤處理、型別系統。最後兩篇是三語言的實作比較,把前面的模型拿來實際對照。
你不需要全部讀完才能用。如果你正在學 Go,可以直接跳到 12(並行 primitives) 和 10(記憶體管理),再回來看 06(並行模型演進) 補上下文。