小巧、快速、可靠。
任選三項。

SQLite 的非同步 I/O 模組


注意: WAL 模式 搭配 PRAGMA synchronous 設為 NORMAL,可避免在交易提交期間呼叫 fsync(),且僅在 檢查點 作業期間呼叫 fsync()。使用 WAL 模式 在很大程度上消除了此非同步 I/O 模組的需求。因此,此模組不再受支援。原始碼仍存在於 SQLite 原始碼樹中,但它不再是任何標準建置的一部分,也不再維護。此文件保留供歷史參考。


通常,當 SQLite 寫入資料庫檔案時,它會等到寫入作業完成後才將控制權回傳給呼叫應用程式。由於寫入檔案系統通常與 CPU 繫結作業相比非常慢,這可能會成為效能瓶頸。非同步 I/O 後端是一個擴充功能,可讓 SQLite 使用背景中執行的獨立執行緒執行所有寫入要求。雖然這不會減少整體系統資源(CPU、磁碟頻寬等),但它確實允許 SQLite 在寫入資料庫時也能快速將控制權回傳給呼叫者。

1.0 功能

使用非同步 I/O 時,寫入要求會由背景中執行的獨立執行緒處理。這表示發起資料庫寫入的執行緒不必等待(有時很慢的)磁碟 I/O 發生。寫入似乎發生得很快,但實際上它在背景中以其通常的慢速發生。

非同步 I/O 似乎能提供更好的回應性,但需要付出代價。您會失去 Durable 屬性。使用 SQLite 的預設 I/O 後端,一旦寫入完成,您就知道您寫入的資訊已安全地儲存在磁碟中。使用非同步 I/O 時,情況並非如此。如果您的程式崩潰,或是在資料庫寫入後但在非同步寫入執行緒完成之前發生斷電,則資料庫變更可能永遠無法寫入磁碟,而資料庫的下一位使用者可能看不到您的變更。

您會因為非同步 I/O 而失去 Durability,但您仍保留 ACID 的其他部分:原子性、一致性及隔離性。許多應用程式在沒有 Durability 的情況下也能正常執行。

1.1 運作方式

非同步 I/O 的運作方式是建立一個 SQLite VFS 物件,並使用 sqlite3_vfs_register() 註冊它。透過此 VFS 開啟的檔案寫入(使用 vfs xWrite() 方法)時,資料不會直接寫入磁碟,而是會放入「寫入佇列」,由背景執行緒處理。

使用非同步 VFS 開啟的檔案讀取(使用 vfs xRead() 方法)時,資料會從磁碟上的檔案和寫入佇列讀取,因此從 vfs 讀取器的觀點來看,xWrite() 似乎已完成。

非同步 I/O VFS 由呼叫 API 函數 sqlite3async_initialize() 和 sqlite3async_shutdown() 註冊(和取消註冊)。有關詳細資訊,請參閱下方的「編譯和使用」區段。

1.2 限制

為了獲得非同步 IO 主要概念的經驗,此實作刻意保持簡單。未來可能會新增其他功能。

例如,根據目前的實作,如果寫入以穩定的串流發生,超過背景寫入執行緒的 I/O 功能,則待處理寫入作業的佇列將無限增長。如果這種情況持續夠久,主機系統可能會用完記憶體。更精密的模組可以追蹤待處理寫入的數量,並在待處理寫入的佇列過大時停止接受新的寫入要求。

1.3 鎖定和並行

使用此非同步 IO 實作的單一處理程序中的多個連線可以同時存取單一資料庫檔案。從使用者的觀點來看,如果所有連線都來自單一處理程序,則「一般」SQLite 和使用非同步後端的 SQLite 提供的並行沒有差別。

如果啟用檔案鎖定(預設啟用),則來自多個處理程序的連線也可以讀取和寫入資料庫檔案。但是,並行會減少,如下所示

檔案鎖定可以在執行階段使用 sqlite3async_control() API(請參閱下方)停用。當使用 NFS 或其他網路檔案系統時,這可能會改善效能,因為可以避免與伺服器之間的同步往返,以建立檔案鎖定。不過,如果在停用檔案鎖定時,多個連線嘗試存取同一個資料庫檔案,應用程式崩潰和資料庫損毀是可能發生的結果。

2.0 編譯和使用

非同步 IO 擴充套件包含一個 C 程式碼檔案 (sqlite3async.c) 和一個標頭檔案 (sqlite3async.h),位於 SQLite 原始碼樹的 ext/async/ 子資料夾 中,定義了應用程式用於啟動和控制模組功能的 C API。

若要使用非同步 IO 擴充套件,請將 sqlite3async.c 編譯為使用 SQLite 的應用程式的一部分。然後使用在 sqlite3async.h 中定義的 API 初始化和設定模組。

非同步 IO VFS API 在 sqlite3async.h 中的註解中有詳細說明。使用 API 通常包含以下步驟

  1. 透過呼叫 sqlite3async_initialize() 函式,向 SQLite 註冊非同步 IO VFS。

  2. 建立背景執行緒來執行寫入作業,並呼叫 sqlite3async_run()。

  3. 使用一般的 SQLite API 透過非同步 IO VFS 讀取和寫入資料庫。

有關詳細資訊,請參閱 sqlite3async.h 標頭檔 中的註解。

3.0 移植

目前,非同步 IO 擴充套件與 win32 系統和支援 pthreads 介面的系統相容,包括 Mac OS X、Linux 和其他各種 Unix。

若要將非同步 IO 擴充套件移植到其他平台,使用者必須為新平台實作互斥鎖和條件變數基本元件。目前沒有外部可用的介面允許這麼做,但修改 sqlite3async.c 中的程式碼以納入新的平台並行基本元件相對容易。在 sqlite3async.c 中搜尋註解字串「移植函式」以取得詳細資訊。然後實作下列各項的新版本

static void async_mutex_enter(int eMutex);
static void async_mutex_leave(int eMutex);
static void async_cond_wait(int eCond, int eMutex);
static void async_cond_signal(int eCond);
static void async_sched_yield(void);

每個上述函式的所需功能都說明在 sqlite3async.c 中的註解中。

此頁面最後修改於 2023-10-10 17:29:48 UTC