注: WAL模式与PRAGMA同步设置为正常交易避免了期间的fsync()调用commit和唯一所调用的fsync()在一个检查点操作。使用WAL模式在很大程度上避免了对该异步I / O模块的需求。因此,不再支持该模块。源代码继续存在于SQLite源树中,但是它不是任何标准构建的一部分,并且不再维护。本文档保留以供历史参考。
通常,当SQLite写入数据库文件时,它将等待直到写入操作完成,然后再将控制权返回给调用应用程序。由于与CPU绑定操作相比,写入文件系统通常非常慢,因此这可能是性能瓶颈。异步I / O后端是使SQLite使用在后台运行的单独线程执行所有写请求的扩展。尽管这不会减少总体系统资源(CPU,磁盘带宽等),但即使在写入数据库时,它也允许SQLite快速将控制权返回给调用方。
使用异步I / O,写请求由在后台运行的单独线程处理。这意味着启动数据库写操作的线程不必等待(有时很慢)磁盘I / O发生。写入似乎很快发生,尽管实际上它是在后台以通常的缓慢速度进行的。
异步I / O似乎可以提供更好的响应能力,但是要付出一定的代价。您将失去耐久财产。使用SQLite的默认I / O后端,一旦写入完成,您就会知道所写入的信息已安全地存储在磁盘上。对于异步I / O,情况并非如此。如果您的程序崩溃或在数据库写入之后但异步写入线程完成之前发生断电,则数据库更改可能永远不会进入磁盘,并且数据库的下一个用户可能看不到您的更改。
您使用异步I / O失去了耐用性,但仍然保留了ACID的其他部分:原子的,一致的和隔离的。许多应用程序在没有耐久性的情况下相处得很好。
异步I / O通过创建SQLite VFS对象 并将其注册到sqlite3_vfs_register()来工作。写入通过此VFS打开的文件时(使用vfs xWrite()方法),数据不会直接写入磁盘,而是放置在“写入队列”中,由后台线程处理。
读取通过异步VFS打开的文件(使用vfs xRead()方法)时,将从磁盘上的文件和写入队列中读取数据,因此从vfs阅读器的角度来看,xWrite()似乎已经完成。
通过调用API函数sqlite3async_initialize()和sqlite3async_shutdown(),可以注册(和注销)异步I / O VFS。有关详细信息,请参见下面的“编译和用法”部分。
为了获得有关异步IO的主要思想的经验,特意将这种实现保持简单。将来可能会添加其他功能。
例如,按照当前的实现方式,如果写入发生在超过后台写入器线程的I / O能力的稳定流中,则挂起的写入操作队列将无限制地增长。如果这种情况持续的时间足够长,则主机系统可能会耗尽内存。一个更复杂的模块可以跟踪挂起的写操作的数量,并在挂起的写操作队列变得太大时停止接受新的写请求。
使用异步IO的此实现的单个进程中的多个连接可以同时访问单个数据库文件。从用户的角度来看,如果所有连接均来自单个进程,则“普通” SQLite和使用异步后端的SQLite提供的并发性之间没有区别。
如果启用了文件锁定(默认情况下已启用),则来自多个进程的连接也可能读写数据库文件。但是并发性降低如下:
当使用异步IO的连接开始数据库事务时,数据库将立即被锁定。但是,只有在写入队列中的所有相关操作都已刷新到磁盘之后,才会释放该锁定。例如,这意味着在发出“ COMMIT ”或“ ROLLBACK ”之后,数据库可能会保持锁定一段时间。
如果使用异步IO的应用程序快速连续执行事务,则可能会将其他数据库用户有效地锁定在数据库之外。这是因为 执行BEGIN时会立即建立数据库锁定。但是,当发生相应的COMMIT或ROLLBACK时,直到刷新了写入队列的相关部分,该锁才会释放。因此,如果在刷新写入队列之前在COMMIT之后跟随BEGIN,则数据库永远不会解锁,从而防止了其他进程访问数据库。
可以在运行时使用sqlite3async_control()API禁用文件锁定(请参见下文)。当避免使用NFS或其他网络文件系统时,这可以提高性能,因为可以避免与服务器建立文件锁定的同步往返。但是,如果在禁用文件锁定时多个连接尝试访问同一数据库文件,则可能导致应用程序崩溃并且数据库损坏。
异步IO扩展由一个C代码文件(sqlite3async.c)和一个头文件(sqlite3async.h)组成,该文件位于SQLite源树的 ext / async /子文件夹中,用于定义应用程序使用的C API激活和控制模块功能。
要使用异步IO扩展,请将sqlite3async.c编译为使用SQLite的应用程序的一部分。然后使用sqlite3async.h中定义的API初始化和配置模块。
sqlite3async.h中的注释中详细描述了异步IO VFS API。使用API通常包括以下步骤:
通过调用sqlite3async_initialize()函数向SQLite注册异步IO VFS。
创建一个后台线程以执行写操作并调用sqlite3async_run()。
使用普通的SQLite API通过异步IO VFS读写数据库。
有关详细信息,请参考 sqlite3async.h头文件中的 注释。
当前,异步IO扩展与win32系统和支持pthreads接口的系统兼容,包括Mac OS X,Linux和其他各种Unix。
要将异步IO扩展移植到另一个平台,用户必须为新平台实现互斥体和条件变量原语。当前没有外部可用的接口允许这样做,但是修改sqlite3async.c中的代码以包括新的平台并发原语是相对容易的。在sqlite3async.c中搜索注释字符串“ PORTING FUNCTIONS”以获取详细信息。然后实施以下各项的新版本:
静态无效async_mutex_enter(int eMutex); 静态无效async_mutex_leave(int eMutex); 静态无效async_cond_wait(int eCond,int eMutex); 静态无效async_cond_signal(int eCond); 静态无效async_sched_yield(void);
sqlite3async.c中的注释中描述了上述每个功能所需的功能。