精华内容
下载资源
问答
  • sqlite线程模式
    2018-03-06 14:42:19

    SQLite支持不同的线程模式:

    1、  Single-thread。这种模式下,锁会失效,多线程同时使用不安全。

    2、  Multi-thread。这种模式下,每个线程需要使用它们各自的连接,一个连接不能同时被多个线程使用。

    3、  Serialized。这种模式下,是多线程安全的。

     

    线程模式可以在编译期(编译SQLite库)、初始化期(应用开始使用SQLite)、运行期(创建连接)选择。通常,运行期会覆盖初始化期的选择,初始化期会覆盖编译器的选择。但是,一旦Single-thread不能被覆盖。

    默认为Serialized。


    编译期选择线程模式

    使用SQLITE_THRWADSAFE选项去选择线程模式。如果没指定该选项,会使用Serialized。

    -DSQLITE_THREADSAFE=0:Single-thread

    -DSQLITE_THREADSAFE=1:Multi-thread

    -DSQLITE_THREADSAFE=2:Serialized

    接口sqlite3_threadsafe()返回值指向的是编译期选定的线程模式。false表示Single-thread,true表示Multi-thread或Serialized。

    如果在编译期选择Single-thread,锁逻辑在构建时会被忽略,所以不能在初始化期或运行期改成Multi-thread或Serialized。

     

    初始化期选择线程模式

    sqlite3_config()接口

     

    运行期选择线程模式

    不能在运行期将单个连接的模型选为single-thread

    sqlite3_open_v2()接口:

    SQLITE_OPEN_NOMUTEX标志会选择multi-thread,SQLITE_OPEN_FULLMUTEX标志会选择serialized

    没指定标志会使用编译期和初始化期的线程模式。

    更多相关内容
  • SQLite线程模式探讨

    2017-07-20 17:46:21
    SQLite源码优化实践》,该文章介绍了微信 iOS 客户端对 SQLite 进行的源码层级的优化,以及其所取得的成果。优化点包括: 多线程并发优化(Busy Retry 的优化)I/O 性能优化(保留 WAL 文件大小,mmap 优化)...

    背景

    最近微信 iOS 团队发表了一篇文章《微信iOS SQLite源码优化实践》,该文章介绍了微信 iOS 客户端对 SQLite 进行的源码层级的优化,以及其所取得的成果。优化点包括:

    1. 多线程并发优化(Busy Retry 的优化)
    2. I/O 性能优化(保留 WAL 文件大小,mmap 优化)
    3. 其他优化(禁用文件锁,禁用内存统计锁)

    其中,单是禁用内存统计锁这点优化,就取得了非常显著的效果,这里引用原文:

    该优化上线后,卡顿监控系统监测到

    • DB写操作造成的卡顿下降超过80%
    • DB读操作造成的卡顿下降超过85%

    看到这结果,首先是满怀惊喜,仅仅是禁用 SQLite 的内存统计这一点,就能使 DB 的卡顿下降超过80%,如果再加上其他优化,那么 SQLite 的性能将实现一次突破!但冷静下来之后,也很快产生怀疑,SQLite 这么成熟的开源数据库,怎么会为了一个内存统计牺牲这么大的性能,要知道,性能是任何一个数据库都极力追求的目标

    所有的猜测都是没用的,实际测一下便知道孰是孰非。为了测试方便,使用自己的开源框架 GYDataCenter,每一行数据包括 NSInteger,double,BOOL,NSDate(double),NSString 5列,测试机器为 iPhone 6s 64G,测试过程如下:

    1. 打开 SQLite 内存统计,分别测试写入 10, 100, 1000,10000,100000 条数据所需时间;
    2. 关闭 SQLite 内存统计,分别测试写入 10, 100, 1000,10000,100000 条数据所需时间;
    3. 对比结果如下,横轴是数据量,纵轴是时间,单位秒;

    从结果我们可以看出,打开或关闭 SQLite 的内存统计,性能基本没差别,仅有的一点点差别都是在误差范围内的。我们又对读操作进行了同样的测试,结果依然没有差别。

    问题出在于哪?究竟是哪个数据有问题?又或者是两个数据都没问题,只是我们打开的方式不对?于是,又重读了一遍微信的文章,发现该文章给出了这样的解释:

    多线程并发时,各线程很容易互相阻塞。
    阻塞虽然也很短暂,但频繁地切换线程,却是个很影响性能的操作,尤其是单核设备。
    因此,如果不需要内存统计的特性,可以通过sqlite3_config(SQLITE_CONFIG_MEMSTATUS, 0)进行关闭。

    加锁和释放锁本身是有性能损耗,但这种损耗是很小的,基本上可以忽略,通常锁所带来的性能损耗正是在于等待其他线程释放锁的时间上。这正是两者的区别所在:

    1. GYDataCenter 使用的是单线程单句柄的模式。对于同一个 db 的所有操作,都放到同一个队列同一个数据库句柄上,排队执行。并通过定时事务自动地把多个操作包在一起,批量地写入磁盘。
    2. 微信 iOS 客户端采用的是多线程多句柄的模式。对于每一个 db,会开多个数据库句柄。对于同一个数据库句柄,同一时间只能在一个队列运行。多个句柄间可以做到读与读,读与写的并发。

    GYDataCenter 在关闭 SQLite 的内存统计后,性能没有得到提升,正是因为 GYDataCenter 使用的是单线程模式,不会有多线程间等待锁的问题。GYDataCenter 从设计上根本地避免了多线程间等待锁的问题。而反观微信的文章,大部分的优化都是在解决多线程间等待锁所引起的性能损耗问题,解决 Busy Retry 使等待线程锁的造成的卡顿下降超过90%,解决内存统计的锁使卡顿下降超过 80%。这似乎也说明了多线程模式带来了很严重的竞争锁的问题。并且,Busy Retry 的线程锁,内存统计的锁只是其中两种锁,可能还有其他各种各样的锁急需优化。

    然而,单从这点就说单线程单句柄模式比多线程多句柄模式好是不正确的,多线程多句柄模式有它自己的优点,其中最明显的一点正是这种模式支持读与读,读与写的并发(WAL 模式下)。那么,我们就来具体分析一下,在移动客户端这个场景下,哪种模式可能更适用。

    多线程多句柄 vs 单线程单句柄

    并发的需求

    要回答这个问题,首先我们要问,在移动客户端下,数据库的读与读,读与写的并发的需求有多强

    还是拿数据说话。在 iPhone 6s 上对微信读书 app 的主要场景进行了数据库并发性的统计。由于不同 app 不尽相同,不同机器性能也不一样,因此下面的统计数据只能做参考意义。

    在上面的结果中,对于n读0写n读1写的情况,多线程模式能起到优化作用。这两种情况分别占了 2% 跟 7%。我们进一步分析发现,出现这两种情况的场景,大多数是在网络请求回来时处理数据。

    分析:移动客户端 app 的运行,都是用户操作驱动的。用户在界面上进行一系列操作,从主线程发起请求,app 响应请求,处理数据,显示结果,一般来说这一系列动作是一条线串起来执行的,没有并发的需求。移动客户端出现的最多的并发情况,在于发起网络请求,和网络请求回来后的数据处理。然而,在网络请求回来的情况下,数据库执行最多的操作是存储返回的数据。对于这种情况,我们都知道,通过事务把多个写操作包在一起能极大地提升性能。下面,我们分析一下两种方案在这种情况下的表现:

    1. 多线程多句柄:如果把写操作放在一个事务中,在事务结束前,其他线程其他句柄的操作都会被卡住,返回 Busy Retry,造成空等待。
    2. 单线程单句柄:自动地把多个写操作包在一个事务中,由于所有操作都放到一个队列,其他的读写操作可以穿插其中,不会被卡住。

    当然,如果你对返回的数据的存储有原子性要求,即要求在存储期间不能有其他任何的读写操作,那么其他读写操作是一定会被卡住的,两种方案都是无法解决的。

    Cache 的管理

    我们都知道,cache 能很好地提升性能。如果采用单线程的方案,cache 的实现就比较简单了。由于所有操作都是在一个队列上排队操作,cache 的维护与查询也在一个队列上排队进行即可,cache 与 db 数据的一致性可以得到保证。

    而如果在多线程多句柄方案上做 cache,可能会有以下两个难点:

    1. 保证 cache 与 db 数据的一到性;
    2. 由于 cache 也是在多线程访问的,因此也需要加锁,也有可能引进竞争锁的性能问题;

    结语

    通过上面的分析,我个人更偏向于使用单线程单句柄的模式。然而,世事无绝对,还是要具体情况具体分析。

    展开全文
  • sqlite线程模式

    2018-03-29 11:08:20
    转载链接:https://blog.csdn.net/szcarewell/article/details/51204064SQLite支持3种线程模式: 单线程:这种模式下,没有进行互斥,多线程使用不安全。禁用所有的mutex锁,并发使用时会出错。当SQLite编译时加了...

    转载链接:https://blog.csdn.net/szcarewell/article/details/51204064

    SQLite支持3种线程模式:

      单线程这种模式下,没有进行互斥,多线程使用不安全。禁用所有的mutex锁,并发使用时会出错。当SQLite编译时加了SQLITE_THREADSAFE=0参数,或者在初始化SQLite前调用sqlite3_config(SQLITE_CONFIG_SINGLETHREAD)时启用。
      多线程这种模式下,只要一个数据库连接不被多个线程同时使用就是安全的。源码中是启用bCoreMutex,禁用bFullMutex。实际上就是禁用数据库连接和prepared statement(准备好的语句)上的锁,因此不能在多个线程中并发使用同一个数据库连接或prepared statement。当SQLite编译时加了SQLITE_THREADSAFE=2参数时默认启用。若SQLITE_THREADSAFE不为0,可以在初始化SQLite前,调用sqlite3_config(SQLITE_CONFIG_MULTITHREAD)启用;或者在创建数据库连接时,设置SQLITE_OPEN_NOMUTEX flag。
      串行:sqlite是线程安全的。启用所有的锁,包括bCoreMutex和bFullMutex 。因为数据库连接和prepared statement都已加锁,所以多线程使用这些对象时没法并发,也就变成串行了。当SQLite编译时加了SQLITE_THREADSAFE =1参数时默认启用。若SQLITE_THREADSAFE不为0,可以在初始化SQLite前,调用sqlite3_config(SQLITE_CONFIG_SERIALIZED)启用;或者在创建数据库连接时,设置SQLITE_OPEN_FULLMUTEX flag  。
        而这里所说的初始化是指调用sqlite3_initialize()函数,这个函数在调用sqlite3_open()时会自动调用,且只有第一次调用是有效的.

       为了达到线程安全,SQLite在编译时必须将 SQLITE_THREADSAFE 预处理宏置为1。在Windows和Linux上, 已编译的好的二进制发行版中都是这样设置的。 如果不确定你所使用的库是否是线程安全的,可以调用 sqlite3_threadsafe() 接口找出。调用sqlite3_threadsafe()可以获得编译期的SQLITE_THREADSAFE参数 。

       也就是说线程模式可以在编译时(通过源码编译sqlite库时)、启动时(使用sqlite的应用程序初始化时)或者运行时(创建数据库连接时)来指定。一般而言,运行时指定的模式将覆盖启动时的指定模式,启动时指定的模式将覆盖编译时指定的模式。但是,单线程模式一旦被指定,将无法被覆盖。默认的线程模式是串行模式。


    编译时选择线程模式
        可以通过定义SQLITE_THREADSAFE宏来指定线程模式。如果没有指定,默认为串行模式。定义宏SQLITE_THREADSAFE=1指定使用串行模式;=0使用单线程模式;=2使用多线程模式。
        sqlite3_threadsafe()函数的返回值可以确定编译时指定的线程模式。如果指定了单线程模式,函数返回false。如果指定了串行或者多线程模式,函数返回true。由于sqlite3_threadsafe()函数要早于多线程模式以及启动时和运行时的模式选择,所以它既不能区别多线程模式和串行模式也不能区别启动时和运行时的模式。
        最后一句可通过sqlite3_threadsafe函数的实现来理解SQLITE_API int sqlite3_threadsafe(void){ return SQLITE_THREADSAFE; }如果编译时指定了单线程模式,那么临界互斥逻辑在构造时就被省略,因此也就无法在启动时或运行时指定串行模式或多线程模式。

    启动时选择线程模式
        假如在编译时没有指定单线程模式,就可以在应用程序初始化时使用sqlite3_config()函数修改线程模式。参数SQLITE_CONFIG_SINGLETHREAD可指定为
    单线程模式,SQLITE_CONFIG_MULTITHREAD指定为多线程模式,SQLITE_CONFIG_SERIALIZED指定为串行模式。

    运行时选择线程模式
        如果没有在编译时和启动时指定为单线程模式,那么每个数据库连接在创建时可单独的被指定为多线程模式或者串行模式,但是不能指定为单线程模式。如果在编译时或启动时指定为单线程模式,就无法在创建连接时指定多线程或者串行模式。
        创建连接时用sqlite3_open_v2()函数的第三个参数来指定线程模式。SQLITE_OPEN_NOMUTEX标识创建多线程模式的连接;SQLITE_OPEN_FULLMUTEX标识创建串行模式的连接。如果没有指定标识,或者使用sqlite3_open()或sqlite3_open16()函数来创建数据库连接,那么在编译时或启动时指定的线程模式将作为默认的线程模式使用。

    展开全文
  • sqlite3_threadsafe:sqlite3_threadsafe()函数的返回值可以确定编译时指定的线程模式(0-单线程模式 1-串行模式 2-多线程模式 源码截图: sqlite_config:sqlite3_config()函数可以修改线程,模式(参数为:SQLITE_...

    sqlite一共有三种线程模式:
    sqlite3_threadsafe:sqlite3_threadsafe()函数的返回值可以确定编译时指定的线程模式(0-单线程模式 1-串行模式 2-多线程模式
    源码截图:
    在这里插入图片描述

    sqlite_config:sqlite3_config()函数可以修改线程,模式(参数为:SQLITE_CONFIG_SINGLETHREAD---单线程 SQLITE_CONFIG_MULTITHREAD----多线程 SQLITE_CONFIG_SERIALIZED-----串行模式)
    源码截图:
    在这里插入图片描述

    1.单线程模式:

    	单线程模式下会禁用所有的mutex锁,并发使用时会出错。当开启单线程模式时sqlite3_threadsafe()==0,
    在初始化sqlit之前可以调用sqlite3_config(SQLITE_CONFIG_SINGLETHREAD)启用。
    

    2.多线程模式:

    	这种模式下,只要一个数据库连接不被多个线程同时使用就是安全的,因为这种模式只启用了bCoreMutex,禁用了bFullMutex。当开启多线程模式时sqlite3_threadsafe()==2,
    在初始化sqlit之前可以调用sqlite3_config(SQLITE_CONFIG_MULTITHREAD)启用。
    

    3.串行模式:

    	这种模式下多线程使用安全的。因为启用了所有的锁,包括bCoreMutex和bFullMutex 。当开启串行模式时sqlite3_threadsafe()==1,
    在初始化sqlit之前可以调用sqlite3_config(SQLITE_CONFIG_SERIALIZED)启用。
    

    初始化demon部分代码

    #include <stdio.h>
    #include <sqlite3.h>
    #include <string.h>
    #include <errno.h>
    
    
    #define DB_PATH "./SQL.db"
    static sqlite3 *db;
    
    
     int sqlite_init(const char *db_path)
    {
    	int ret;
    
    	if (NULL == db_path) {
    		perror("sqlite_init  error");
    		return -1;
    	}
    
    	//判断是否启用串行模式
    	if (sqlite3_threadsafe() != 1) {
    		ret = sqlite3_config(SQLITE_CONFIG_SERIALIZED);//设置为串行模式
    
    		if (ret != SQLITE_OK) {
    			printf("SQLite3 is not compiled with serialized threading mode!\n");
    			return -1;
    		}
    	}
    
    	//sqlite初始化
    	ret = sqlite3_initialize();
    	if (ret != SQLITE_OK) {
    		perror("database_init sqlite_initalize error");
    		return -1;;
    	}
    
    	ret = sqlite3_open(db_path,&db);
    	if (ret) {
    		printf("Can't open sql: %s", sqlite3_errmsg(db));
    		return -1;
    	}
    
    	return 0;
     }
    
    int main()
    {
    	sqlite_init(DB_PATH);
    	
    	return 0;
    }
    
    

    运行截图:
    在这里插入图片描述

    展开全文
  • SQLite支持3种线程模式

    2020-11-13 15:15:23
    相关文章 1、SQLite线程使用总结----https://www.cnblogs.com/liaj/p/4015219.html 2、关于多线程使用sqlite3的问题----... 单线程:这种模式下,没有进行互斥,多线程使用不安全。禁用所有的mute..
  • sqlite线程模式的设置

    2019-10-03 13:56:19
    0:单线程模式,即内部不做mutex保护,多线程运行sqlite不安全。 1:多线程的串行模式,sqlite帮助多线程实现串行化。 2:多线程的并发模式,要求同一个时刻,同一个连接不被多个线程使用。 (2)打开数据库阶段 ...
  • 总结了一下Qt中sqlite线程操作遇到的几个问题,希望能对有需要的朋友一点帮助 总结了一下Qt中sqlite线程操作遇到的几个问题,希望能对有需要的朋友一点帮助
  • #SQLITE_配置_单线程 为单线程模式 #SQLITE_配置_多线程 各个线程使用不同的连接和准备的SQL语句 #SQLITE_配置_串行化 启用所有互斥锁,多个线程都可以使用相同的连接和准备的SQL语句 当然还有一些配置我没有封装完...
  • sqlite读写锁和线程模式

    万次阅读 2019-06-14 18:06:40
    sqlite读写锁 SQLite3总共有三种事务类型:BEGIN [ DEFERRED /IMMEDIATE / EXCLUSIVE ] TRANSCATION,提供以下五种的文件锁状态,按锁的级别依次是:UNLOCKED / SHARED / RESERVERD / PENDING / EXCLUSIVE。 1). ...
  • #SQLITE_配置_单线程 为单线程模式。#SQLITE_配置_多线程 各个线程使用不同的连接和准备的SQL语句。#SQLITE_配置_串行化 启用所有互斥锁,多个线程都可以使用相同的连接和准备的SQL语句。当然还有一些配置我没有封装...
  • sqlite3线程安全

    千次阅读 2022-04-28 13:40:36
    sqlite3 sqlite3.c文件中有sqlite_threadsafe的定义 /* ** The SQLITE_THREADSAFE macro must be defined as 0, 1, or 2. ** 0 means mutexes are permanently disable and the library is never ** threadsafe. 1 ...
  • SQLite支持3种线程模式: 单线程:这种模式下,没有进行互斥,多线程使用不安全。禁用所有的mutex锁,并发使用时会出错。当SQLite编译时加了SQLITE_THREADSAFE=0参数,或者在初始化SQLite前调用sqlite3_config...
  • SQLite线程模式

    千次阅读 2018-10-12 18:29:52
    SQLite
  • SQLite 线程安全和并发

    2021-03-07 03:53:14
    SQLite线程SQLite线程安全的。线程模型SQLite支持如下三种线程模型单线程模型这种模型下,所有互斥锁都被禁用,同一时间只能由一个线程访问。多线程模型这种模型下,一个连接在同一时间内只有一个线程使用就是...
  • SQLite线程安全吗?SQLite的事务事务概述两种方法提速事务提交事务执行过程WAL模式引用 概述 SQLite支持三种不同的线程模式: 单线程。在此模式下,所有互斥锁都被禁用,并且SQLite一次不能在多个线程中...
  • Linux下sqlite3多线程和串行模式

    千次阅读 2017-01-23 20:39:47
    sqlite3支持三种模式:单线程模式,多线程模式和串行模式。 模式可在编译,启动时或运行时设置,一般来讲,启动时的设置会覆盖编译时的设置,运行时则会覆盖启动时或编译时的设置。但是一旦单线程模式被设置之后就不...
  • 由此可见,要想保证线程安全的话,可以有这4种方式:SQLite使用单线程模式,用一个专门的线程访问数据库。SQLite使用单线程模式,用一个线程队列来访问数据库,队列一次只允许一个线程执行,队列里的线程共用一个...
  • SQLite线程使用总结

    千次阅读 2019-06-19 10:44:04
    SQLite支持3种线程模式:  单线程:这种模式下,没有进行互斥,多线程使用不安全。禁用所有的mutex锁,并发使用时会出错。当SQLite编译时加了SQLITE_THREADSAFE=0参数,或者在初始化SQLite前调用sqlite3_config...
  • android关于多线程操作sqlite知识点

    千次阅读 2016-01-03 15:09:04
    SQLiteDatabase对CRUD操作都会加上一个锁(因为是db文件,所以精确至数据库级),这就保证了在同一时间你只能进行一项操作,无论是不是在同一个线程中,这就导致了如果你在程序中对SQLiteOpenHelper使用了单例模式,...
  • 在python中多线程访问sqlite3数据库

    千次阅读 2021-03-17 02:23:40
    不过,此模块在使用时也有限制,同一个数据库连接,不能在不同线程中共享。import threadingimport sqlite3sqlite_mutex = threading.Lock()db = sqlite3.connect('tdb2')def initdb():try:db.executescript(""...
  • sqlite线程安全与并发

    万次阅读 2018-03-29 11:30:21
    SQLite 线程安全和并发SQLite线程SQLite 是线程安全的。线程模型SQLite 支持如下三种线程模型单线程模型 这种模型下,所有互斥锁都被禁用,同一时间只能由一个线程访问。多线程模型 这种模型下,一个连接在...
  • sqlite线程访问

    千次阅读 2020-07-17 14:15:30
    1.SQLite支持如下三种线程模型 单线程模型这种模型下,所有互斥锁都被禁用,同一时间只能由一个线程...2.可以在编译期设定编译参数值来确定使用哪种模式,也可以在运行时调用函数sqlite3_config(SQLITE_CONFIG_MULT...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 25,078
精华内容 10,031
关键字:

sqlite线程模式