發布至今18年,爲什麼SQLite一定要用C語言來開發?

發佈至今18年,為什麼SQLite一定要用C語言來開發?

SQLite 選擇 C 語言的理由是什麼?為什麼不選擇 Go 或者 Rust?

1、C語言是最好的

SQLite 在 2000 年 5 月 29 日發佈,並一直使用 C 語言實現。C 語言一直是實現 SQLite 這類軟件庫的最佳語言,目前還沒有計劃使用其他編程語言重新開發 SQLite。

C語言是實現 SQLite 的最佳語言,原因有四:性能、兼容性、低依賴性、穩定性

性能

像 SQLite 這樣低級庫速度必須要快。確實,SQLite 的速度很快,甚至比文件系統要快上 35%。

C語言非常適合用來開發這種對速度有要求的代碼。C 語言有時被稱為“可移植的彙編語言”。它讓開發人員能夠儘可能地靠近底層硬件,同時仍然可以保持跨平臺可移植性。

有些語言聲稱自己“與 C 語言一樣快”,但卻沒有一門語言敢聲稱在作為通用目的編程時比 C 語言快,因為真的沒有。

兼容性

幾乎所有系統都能夠調用用 C 語言編寫的庫,但不一定都能調用使用其他語言實現的庫。

例如,使用 Java 開發的 Android 應用程序也能調用 SQLite(通過適配器)。如果使用 Java 開發 SQLite,那麼對 Android 來說可能會更加方便,因為接口會更簡單。但是,在 iPhone 上,應用程序是用 Objective-C 或 Swift 開發的,它們都不能調用使用 Java 編寫的庫。因此,如果使用 Java 開發,SQLite 將無法在 iPhone 上使用。

低依賴性

使用 C 語言開發的庫沒有太多運行時依賴。SQLite 的最低配置只依賴標準 C 庫的以下幾個例程:memcmp()、strcmp()、memcpy()、strlen()、memmove()、strncmp()、memset()。

對於更完整的版本,SQLite 還使用了 malloc() 和 free() 之類的例程以及用於打開、讀取、寫入和關閉文件的操作系統接口。但即便如此,依賴項的數量仍然非常少。相比之下,其他“現代”語言通常需要加載數兆字節帶有成千上萬個接口的運行時。

穩定性

C語言陳舊乏味,是一門眾所周知且易於理解的語言。這正好契合了 SQLite 的要求。如果沒有 C語言這樣的語言,開發一個小型、快速、可靠的數據庫引擎是很困難的。

2、為什麼 SQLite 不使用面嚮對象語言來開發?

一些程序員無法想象怎麼可以使用非“面向對象”的語言來開發像 SQLite 這樣的複雜系統。那麼為什麼 SQLite 沒有用 C++ 或 Java 來開發?

  1. 使用 C++ 或 Java 編寫的庫通常只能由以相同語言開發的應用程序使用。使用 Haskell 或 Java 開發的應用程序很難調用 C++ 庫。反過來,用 C 語言編寫的庫可以在其他編程語言中調用。
  2. 面向對象是一種設計模式,而不是一種編程語言。你可以使用任何語言(包括彙編語言)實現面向對象編程,只是某些語言(例如 C++ 或 Java)讓面向對象變成變得更容易而已。但你仍然可以用像 C 這樣的語言進行面向對象編程。
  3. 面向對象並不是唯一有效的設計模式。很多程序員被教導使用純粹的面向對象方式進行思考。對象通常是分解問題的好方法,但對象不是唯一的方法,而且不一定是分解問題的最佳方法。有時候,過程式的代碼更容易編寫,更易於維護和理解,並且比面向對象的代碼運行地更快。
  4. 最初在開發 SQLite 時,Java 還只是一門年輕而不成熟的語言。C++ 比較成熟一些,但正在經歷成長的痛苦時期,當時很難找到兩種能夠以相同方式工作的 C++ 編譯器。所以,在當時 C 語言絕對是一個更好的選擇。現在這種情況沒有那麼明顯,但現在重新開發 SQLite 幾乎沒有任何好處。

3、為什麼 SQLite 不使用“安全”的編程語言來開發?

最近人們對像 Rust 或 Go 這樣的“安全”編程語言很感興趣。在使用這些編程語言時,不太可能或至少很難犯下常見的編程錯誤,如內存洩漏或數組溢出。

因此,經常會有人問為什麼 SQLite 不使用“安全”的語言來開發。

  1. 在 SQLite 出現後的頭 10 年中,所謂的安全的編程語言並不存在。SQLite 可以使用 Go 語言或 Rust 重新開發,但這樣做可能會引入更多的錯誤,並且也可能導致代碼運行得更慢。
  2. 安全的編程語言解決了容易出現的問題:內存洩漏、use-after-free 錯誤、數組溢出等。安全語言在解決 SQL 計算結果這個問題上,不會比普通的 C 語言代碼提供更多的幫助。
  3. 安全語言通常聲稱自己有助於防止安全漏洞。話是沒錯,但 SQLite 並不是一個對安全特別敏感的庫。如果應用程序運行了不受信任且未經驗證的 SQL,那麼它已經存在更大的安全問題(SQL 注入),沒有哪一門“安全”的語言可以修復這個問題。確實,應用程序有時會從不受信任的來源導入 SQLite 二進制數據庫文件,這樣可能會帶來潛在的威脅。但是,SQLite 中的這種代碼路徑是很有限的,並且經過了良好的測試。SQLite 還為希望讀取不受信任數據庫的應用程序提供了預驗證例程,幫助應用程序檢測潛在的威脅。
  4. 一些“安全”語言(例如 Go 語言)不喜歡使用 assert()。但是使用 assert() 是保持 SQLite 可維護性的重要前提。
  5. 安全語言會插入額外的分支邏輯來執行其他一些操作,比如驗證數組訪問是否越界。而在正確的代碼中,永遠不會使用這些分支邏輯。這也意味著機器代碼不會 100%被測試到,而這卻恰好是 SQLite 質量策略的重要組成部分。
  6. 安全語言通常希望在遇到內存不足(OOM)時終止運行。SQLite 卻被設計成能夠從 OOM 中正常恢復。目前還不知道該如何在安全語言中實現這一特性。
  7. 現在所有的安全語言都是新生兒。SQLite 的開發人員對計算機語言研究人員努力開發更容易、更安全的編程語言表示讚賞,我們鼓勵他們繼續努力下去。但在實現 SQLite 時,我們對陳舊乏味的 C 語言更感興趣。

SQLite 可能有一天會使用 Rust 重新開發。由於 Go 語言討厭 assert(),因此不太可能使用 Go 語言。但使用 Rust 也只是一種可能性。如果要使用 Rust 重新開發 SQLite,需要滿足一些先決條件:

  1. Rust 需要變得更成熟,減慢演化速度,並且要變得更加陳舊乏味。
  2. Rust 需要證明它可以用於構建能夠在所有其他編程語言中調用的通用庫。
  3. Rust 需要證明它可以生成適用於嵌入式設備的代碼,包括缺少操作系統的設備。
  4. Rust 需要提供可以對二進制文件進行 100%分支覆蓋測試的工具。
  5. Rust 需要提供一種能夠從 OOM 錯誤中優雅恢復的機制。
  6. Rust 需要證明它可以完成 C 語言在 SQLite 中所做的各種工作而不會降低性能。

作者 | SQLite

譯者 | 薛命燈


分享到:


相關文章: