用于 SQLite 的异步 I/O 模块(二十四)

news2025/6/18 6:41:59

返回:SQLite—系列文章目录   

上一篇:SQLite的PRAGMA 声明(二十三)

下一篇:SQLite、MySQL 和 PostgreSQL 数据库速度比较(本文阐述时间很早比较,不具有最新参考性)(二十五)

注意:将 PRAGMA 同步设置为 NORMAL 的 WAL 模式可避免对 fsync() 并且仅在 检查点操作。WAL 模式的使用在很大程度上避免了 需要这个异步 I/O 模块。因此,此模块不再 支持。源代码继续存在于 SQLite 源代码树中, 但它不是任何标准构建的一部分,也不再维护。 保留此文档以供历史参考。


通常,当SQLite写入数据库文件时,它会等到写入 在将控制权返回给调用应用程序之前,操作已完成。 由于与 CPU 相比,写入文件系统通常非常慢 绑定操作,这可能是性能瓶颈。异步 I/O backend 是一个扩展,它使 SQLite 执行所有写入请求 使用在后台运行的单独线程。虽然这没有 减少整体系统资源(CPU、磁盘带宽等),确实如此 允许 SQLite 快速将控制权返回给调用方,即使在写入 数据库。

1.0 功能

使用异步 I/O 时,写入请求由单独的线程处理 在后台运行。这意味着启动的线程 数据库写入不必等待(有时很慢)磁盘 I/O 发生。写入似乎发生得非常快,尽管实际上 它在后台以通常的缓慢速度发生。

异步 I/O 似乎提供了更好的响应能力,但要付出代价。 您将失去 Durable 属性。使用 SQLite 的默认 I/O 后端, 写入完成后,您就知道您写入的信息是 安全地在磁盘上。对于异步 I/O,情况并非如此。如果 程序崩溃或数据库断电后 写入,但在异步写入线程完成之前,则 数据库更改可能永远不会进入磁盘,而 数据库可能看不到您的更改。

异步 I/O 会失去持久性,但仍会保留 ACID 的其他部分:原子、一致和隔离。多 应用程序在没有耐用性的情况下相处得很好。

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 提供的并发性之间 使用异步后端。

如果启用了文件锁定(默认情况下启用),则连接 还可以从多个进程读取和写入数据库文件。 但是,并发性降低如下:

  • 当使用异步 IO 的连接启动数据库时 事务,数据库立即被锁定。然而, 在所有相关操作之后,锁不会释放 在写入队列中已刷新到磁盘。这意味着 (例如)数据库可能在某些情况下保持锁定状态 发出“COMMIT”或“ROLLBACK”后的时间。

  • 如果使用异步 IO 的应用程序执行事务 在快速连续的情况下,其他数据库用户可以有效地 锁定在数据库之外。这是因为当执行 BEGIN 时,会立即建立数据库锁。但 当发生相应的 COMMIT 或 ROLLBACK 时,锁定 直到写入队列的相关部分才被释放 已被冲洗。因此,如果遵循 COMMIT 在刷新写入队列之前,通过 BEGIN 将数据库 永不解锁,阻止其他进程访问 数据库。

可以在运行时使用 sqlite3async_control() 禁用文件锁定 API(见下文)。这可能会提高 NFS 或其他 NFS 或其他 网络文件系统,因为与服务器的同步往返是 避免了建立文件锁所需的条件。但是,如果多个 连接在文件锁定时尝试访问同一数据库文件 被禁用,应用程序崩溃和数据库损坏是可能的 结果。

2.0 编译与使用

异步 IO 扩展由 C 代码的单个文件组成 (sqlite3async.c) 和头文件 (sqlite3async.h),位于 SQLite 源代码树的 ext/async/ 子文件夹中,用于定义 应用程序用于激活和控制模块的 C API 功能性。

若要使用异步 IO 扩展,请将 sqlite3async.c 编译为 使用 SQLite 的应用程序的一部分。然后使用定义的 API 在 sqlite3async.h 中初始化和配置模块。

异步 IO VFS API 在注释中进行了详细描述。 sqlite3async.h. 使用 API 通常包括以下步骤:

  1. 通过调用 sqlite3async_initialize() 函数。

  2. 创建后台线程以执行写入操作和调用 sqlite3async_run()。

  3. 使用普通的 SQLite API 通过以下方式读取和写入数据库 异步 IO VFS。

有关详细信息,请参阅 sqlite3async.h 头文件中的注释。或本文编写时最新代码如下:


#ifndef __SQLITEASYNC_H_
#define __SQLITEASYNC_H_ 1

/*
** Make sure we can call this stuff from C++.
*/
#ifdef __cplusplus
extern "C" {
#endif

#define SQLITEASYNC_VFSNAME "sqlite3async"

/*
** THREAD SAFETY NOTES:
**
** Of the four API functions in this file, the following are not threadsafe:
**
**   sqlite3async_initialize()
**   sqlite3async_shutdown()
**
** Care must be taken that neither of these functions is called while 
** another thread may be calling either any sqlite3async_XXX() function
** or an sqlite3_XXX() API function related to a database handle that
** is using the asynchronous IO VFS.
**
** These functions:
**
**   sqlite3async_run()
**   sqlite3async_control()
**
** are threadsafe. It is quite safe to call either of these functions even
** if another thread may also be calling one of them or an sqlite3_XXX()
** function related to a database handle that uses the asynchronous IO VFS.
*/

/*
** Initialize the asynchronous IO VFS and register it with SQLite using
** sqlite3_vfs_register(). If the asynchronous VFS is already initialized
** and registered, this function is a no-op. The asynchronous IO VFS
** is registered as "sqlite3async".
**
** The asynchronous IO VFS does not make operating system IO requests 
** directly. Instead, it uses an existing VFS implementation for all
** required file-system operations. If the first parameter to this function
** is NULL, then the current default VFS is used for IO. If it is not
** NULL, then it must be the name of an existing VFS. In other words, the
** first argument to this function is passed to sqlite3_vfs_find() to
** locate the VFS to use for all real IO operations. This VFS is known
** as the "parent VFS".
**
** If the second parameter to this function is non-zero, then the 
** asynchronous IO VFS is registered as the default VFS for all SQLite 
** database connections within the process. Otherwise, the asynchronous IO
** VFS is only used by connections opened using sqlite3_open_v2() that
** specifically request VFS "sqlite3async".
**
** If a parent VFS cannot be located, then SQLITE_ERROR is returned.
** In the unlikely event that operating system specific initialization
** fails (win32 systems create the required critical section and event 
** objects within this function), then SQLITE_ERROR is also returned.
** Finally, if the call to sqlite3_vfs_register() returns an error, then 
** the error code is returned to the user by this function. In all three
** of these cases, intialization has failed and the asynchronous IO VFS
** is not registered with SQLite.
**
** Otherwise, if no error occurs, SQLITE_OK is returned.
*/ 
int sqlite3async_initialize(const char *zParent, int isDefault);

/*
** This function unregisters the asynchronous IO VFS using 
** sqlite3_vfs_unregister().
**
** On win32 platforms, this function also releases the small number of 
** critical section and event objects created by sqlite3async_initialize().
*/ 
void sqlite3async_shutdown(void);

/*
** This function may only be called when the asynchronous IO VFS is 
** installed (after a call to sqlite3async_initialize()). It processes
** zero or more queued write operations before returning. It is expected
** (but not required) that this function will be called by a different 
** thread than those threads that use SQLite. The "background thread"
** that performs IO.
**
** How many queued write operations are performed before returning 
** depends on the global setting configured by passing the SQLITEASYNC_HALT
** verb to sqlite3async_control() (see below for details). By default
** this function never returns - it processes all pending operations and 
** then blocks waiting for new ones.
**
** If multiple simultaneous calls are made to sqlite3async_run() from two
** or more threads, then the calls are serialized internally.
*/
void sqlite3async_run(void);

/*
** This function may only be called when the asynchronous IO VFS is 
** installed (after a call to sqlite3async_initialize()). It is used 
** to query or configure various parameters that affect the operation 
** of the asynchronous IO VFS. At present there are three parameters 
** supported:
**
**   * The "halt" parameter, which configures the circumstances under
**     which the sqlite3async_run() parameter is configured.
**
**   * The "delay" parameter. Setting the delay parameter to a non-zero
**     value causes the sqlite3async_run() function to sleep for the
**     configured number of milliseconds between each queued write 
**     operation.
**
**   * The "lockfiles" parameter. This parameter determines whether or 
**     not the asynchronous IO VFS locks the database files it operates
**     on. Disabling file locking can improve throughput.
**
** This function is always passed two arguments. When setting the value
** of a parameter, the first argument must be one of SQLITEASYNC_HALT,
** SQLITEASYNC_DELAY or SQLITEASYNC_LOCKFILES. The second argument must
** be passed the new value for the parameter as type "int".
**
** When querying the current value of a paramter, the first argument must
** be one of SQLITEASYNC_GET_HALT, GET_DELAY or GET_LOCKFILES. The second 
** argument to this function must be of type (int *). The current value
** of the queried parameter is copied to the memory pointed to by the
** second argument. For example:
**
**   int eCurrentHalt;
**   int eNewHalt = SQLITEASYNC_HALT_IDLE;
**
**   sqlite3async_control(SQLITEASYNC_HALT, eNewHalt);
**   sqlite3async_control(SQLITEASYNC_GET_HALT, &eCurrentHalt);
**   assert( eNewHalt==eCurrentHalt );
**
** See below for more detail on each configuration parameter.
**
** SQLITEASYNC_HALT:
**
**   This is used to set the value of the "halt" parameter. The second
**   argument must be one of the SQLITEASYNC_HALT_XXX symbols defined
**   below (either NEVER, IDLE and NOW).
**
**   If the parameter is set to NEVER, then calls to sqlite3async_run()
**   never return. This is the default setting. If the parameter is set
**   to IDLE, then calls to sqlite3async_run() return as soon as the
**   queue of pending write operations is empty. If the parameter is set
**   to NOW, then calls to sqlite3async_run() return as quickly as 
**   possible, without processing any pending write requests.
**
**   If an attempt is made to set this parameter to an integer value other
**   than SQLITEASYNC_HALT_NEVER, IDLE or NOW, then sqlite3async_control() 
**   returns SQLITE_MISUSE and the current value of the parameter is not 
**   modified.
**
**   Modifying the "halt" parameter affects calls to sqlite3async_run() 
**   made by other threads that are currently in progress.
**
** SQLITEASYNC_DELAY:
**
**   This is used to set the value of the "delay" parameter. If set to
**   a non-zero value, then after completing a pending write request, the
**   sqlite3async_run() function sleeps for the configured number of 
**   milliseconds.
**
**   If an attempt is made to set this parameter to a negative value,
**   sqlite3async_control() returns SQLITE_MISUSE and the current value
**   of the parameter is not modified.
**
**   Modifying the "delay" parameter affects calls to sqlite3async_run() 
**   made by other threads that are currently in progress.
**
** SQLITEASYNC_LOCKFILES:
**
**   This is used to set the value of the "lockfiles" parameter. This
**   parameter must be set to either 0 or 1. If set to 1, then the
**   asynchronous IO VFS uses the xLock() and xUnlock() methods of the
**   parent VFS to lock database files being read and/or written. If
**   the parameter is set to 0, then these locks are omitted.
**
**   This parameter may only be set when there are no open database
**   connections using the VFS and the queue of pending write requests
**   is empty. Attempting to set it when this is not true, or to set it 
**   to a value other than 0 or 1 causes sqlite3async_control() to return
**   SQLITE_MISUSE and the value of the parameter to remain unchanged.
**
**   If this parameter is set to zero, then it is only safe to access the
**   database via the asynchronous IO VFS from within a single process. If
**   while writing to the database via the asynchronous IO VFS the database
**   is also read or written from within another process, or via another
**   connection that does not use the asynchronous IO VFS within the same
**   process, the results are undefined (and may include crashes or database
**   corruption).
**
**   Alternatively, if this parameter is set to 1, then it is safe to access
**   the database from multiple connections within multiple processes using
**   either the asynchronous IO VFS or the parent VFS directly.
*/
int sqlite3async_control(int op, ...);

/*
** Values that can be used as the first argument to sqlite3async_control().
*/
#define SQLITEASYNC_HALT          1
#define SQLITEASYNC_GET_HALT      2
#define SQLITEASYNC_DELAY         3
#define SQLITEASYNC_GET_DELAY     4
#define SQLITEASYNC_LOCKFILES     5
#define SQLITEASYNC_GET_LOCKFILES 6

/*
** If the first argument to sqlite3async_control() is SQLITEASYNC_HALT,
** the second argument should be one of the following.
*/
#define SQLITEASYNC_HALT_NEVER 0       /* Never halt (default value) */
#define SQLITEASYNC_HALT_NOW   1       /* Halt as soon as possible */
#define SQLITEASYNC_HALT_IDLE  2       /* Halt when write-queue is empty */

#ifdef __cplusplus
}  /* End of the 'extern "C"' block */
#endif
#endif        /* ifndef __SQLITEASYNC_H_ */

3.0 移植

目前,异步 IO 扩展与 win32 系统兼容 以及支持 pthreads 接口的系统,包括 Mac OS X、Linux、 和其他 Unix 变体。

若要将异步 IO 扩展移植到另一个平台,用户必须 为新平台实现互斥锁和条件变量基元。 目前没有外部可用的接口可以允许这样做,但是 修改 sqlite3async.c 中的代码以包含新平台 并发原语相对容易。在 sqlite3async.c 中搜索 有关详细信息,请使用注释字符串“PORTING FUNCTIONS”。然后实施 以下各项的新版本:

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 的注释中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1598092.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【数据结构|C语言版】单链表应用

前言1. 基于单链表实现通讯录1.1 知识要求1.2 功能要求 2. 代码总结2.1 SeqList.h2.2 SeqList.c2.3 Contact.h2.4 Contact.c2.5 test.c 后言 上期回顾:【数据结构|C语言版】单链表 前言 各位小伙伴大家好!上期小编讲解了单链表相关知识,在此…

linux 设置定时任务---学习

1、设置定时任务 crontab -e 设置格式参考:【Linux】Linux crontab 命令定时任务设置_crontab 设置每天10:30执行-CSDN博客 测试过程: */1 * * * * /root/cronjob.sh 脚本内容: echo "hell0 cronjob" >> /root/test/hello.txt 实现…

腾讯云服务器CVM标准型S8实例CPU内存、网络和存储性能测评

腾讯云第八代云服务器标准型S8实例基于全新优化虚拟化平台,CPU采用Intel Emerald Rapids 全新处理器,睿频3.0GHz,内存采用最新DDR5,默认网络优化,最高内网收发能力达4500万pps,最高内网带宽可支持120Gbps。…

游戏生成式 AI:编织梦想,避开阴影

想象一下,一个沉浸式的游戏世界中玩家遇到的每个 NPC 都由 AI 驱动,他们能与玩家进行互动,从改变游戏体验。据 Inword 一项研究显示,绝大多数游戏玩家渴望这种互动,愿意投入更多的时间和金钱来玩这种由 AI 驱动的游戏。…

亚马逊、沃尔玛自养号测评技术解析:如何降低潜在风险

亚马逊等电商平台在全球范围内迅速扩张,竞争愈发激烈。为提升产品排名和销量,众多卖家选择采用自养号测评的策略。然而,自养号测评技术并非完美无缺,它存在着一定的技术局限性。由于缺乏对自养号原理及底层环境搭建的深入理解&…

如何在Vue3中使用H.265视频EasyPlayer.js流媒体播放器?

H5无插件流媒体播放器EasyPlayer属于一款高效、精炼、稳定且免费的流媒体播放器,可支持多种流媒体协议播放,可支持H.264与H.265编码格式,性能稳定、播放流畅,能支持WebSocket-FLV、HTTP-FLV,HLS(m3u8&#…

操作系统(第五周 第一二堂总结)

目录 回顾 前景知识 概述 定义 进程和线程的关系 进程和线程的区别 线程优缺点 优点: 缺点: 易混概念 线程实现方式 线程的类型: ​编辑 多线程模型: 线程函数 头文件: 线程创建函数: 线…

k8s控制器(五)_____DaemonSet

DaemonSet控制器 DaemonSet控制器是Kubernetes中的一种控制器,用于确保集群中的每个节点都运行一个Pod的副本。它通常用于在整个集群中部署一些系统级别的服务: 在每一个node节点运行一个存储服务,例如gluster,ceph。在每一个no…

DRF视图组件(2个视图基类、5个视图扩展类、9个视图子类、视图集和路由映射)

DRF视图组件(2个视图基类、5个视图扩展类、9个视图子类、视图集和路由映射) 目录 DRF视图组件(2个视图基类、5个视图扩展类、9个视图子类、视图集和路由映射)2个视图基类mixins的5个视图扩展类generics的9个视图子类视图集自定制返回格式自动生成路由(SimpleRouter)action装饰器…

非监督学习的模型为条件概率分布P(z|x)和p(x|z)的区别

在无监督学习中,假设X是输入空间,Z是输出的隐式结构空间,要学习的模型非概率模型情况可以表示为函数zg(x),概率模型情况下表示为条件概率分布P(z|x)或p(x∣z),它们 都可以用来描述数据中的潜在结…

[ROS 系列学习教程] 建模与仿真 - URDF 语法介绍

ROS 系列学习教程(总目录) 本文目录 一、robot标签二、link标签三、joint标签 URDF文件中使用XML格式描述的机器人模型,下面介绍URDF的XML标签。 一、robot标签 机器人描述文件中的根元素必须是robot,所有其他元素必须封装在其中。 属性 name&#x…

JetBrains Rider 2024.1 发布 - 快速且强大的跨平台 .NET IDE

JetBrains Rider 2024.1 发布 - 快速且强大的跨平台 .NET IDE 请访问原文链接:JetBrains Rider 2024.1 (macOS, Linux, Windows) - 快速且强大的跨平台 .NET IDE,查看最新版。原创作品,转载请保留出处。 作者主页:sysin.org Jet…

jpa使用Querydsl需要规避的一些坑

在使用Spring Data JPA时,通常会使用Querydsl来构建类型安全的查询。在Querydsl中,为了区分实体类与Querydsl查询类,习惯上会给查询类的前缀添加一个"Q",表示该类是一个查询类。这样做可以有效地避免实体类与查询类之间…

数据结构和算法(哈希表和图(A*算法精讲))

一 、哈希表 1.1 哈希表原理精讲 哈希表-散列表,它是基于快速存取的角度设计的,也是一种典型的“空间换时间”的做法 键(key): 组员的编号如,1、5、19。。。 值(value): 组员的其它信息(包含性别、年龄和…

pyqt实现星三角减压启动

这个对于plc上实现是非常容易得。它本来就是逻辑控制器,如果用代码实现它,该怎么做呢?这个实现起来看似简单,实则是有不少坑的(大神除外)。我一直想用类来封装,让它继承QObject,为啥非要继承QOb…

电信网络如何异地共享文件?

电信异地共享文件是指在不同地区的电信网络下,通过使用特定技术实现文件的共享和传输。在传统的网络环境中,由于网络限制和复杂的网络设置,实现跨地区的文件共享是一个具有挑战性的任务。随着技术的不断进步,现在可以利用电信异地…

Spring Boot | SpringBoot对 “SpringMVC“的 “整合支持“、SpringMVC“功能拓展实现“

目录: SpringMVC 的 “整合支持” ( 引入"Web依赖启动器",几乎可以在无任何额外的配置的情况下进行"Web开发")1.SpringMVC "自动配置" 介绍 ( 引入Web依赖启动器"后,SpringBoot会自动进行一些“自动配置”&#xff0…

文章解读与仿真程序复现思路——中国电机工程学报EI\CSCD\北大核心《应用图论建模输电网的电力现货市场出清模型》

本专栏栏目提供文章与程序复现思路,具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

【cuda\cudnn安装教程】以及环境变量设置(以cuda11.8为例)

【cuda\cudnn安装教程】以cuda11.8为例 cuda11.8安装 安装的时候一切都是按默认安装就好,地址也是默认路径 cudnn安装 下载需要登陆,按要求注册就好 将cudnn压缩包中的内容复制到cuda的安装路径中,进行替换,如下图 验证cuda是否…

可视化报表Superset

文章目录 一、Superset入门与安装1、Superset概述2、安装Python环境2.1 安装Miniconda2.2 创建Python3.7环境 3、Superset部署3.1 安装Superset3.2 启动Supterset3.3 superset启停脚本 4、docker部署 二、Superset使用与实战1、对接MySQL数据源2、制作仪表盘与图表 一、Superse…