用得是自带的 sqlite3 库,可能有 100 个左右的线程吧,目前是每个线程拥有一个单独的连接,所有连接的插入间隔大约是 0.00x 秒,会出现 datebase is locked 错误,请问怎么处理呢?
1
mansur 2017-01-18 22:32:31 +08:00
弄一个队列写吧
|
2
murmur 2017-01-18 22:55:55 +08:00
我怎么印象中 sqlite 用排队+锁的机制比多线程还要好一点
100 线程的话为啥不考虑 mysql 啊 |
3
hosiet 2017-01-18 22:57:40 +08:00 via Android
写入发现被锁了就循环多试几次嘛,可以给个重试上限(例如五次,或者没上限也行)以及重试时间间隔等等。
不过我记得好像有阻塞的写法吧,就是完成写入才返回那种。不知道你用的是什么编程语言? |
6
hosiet 2017-01-18 23:02:18 +08:00 via Android
糟糕没看节点( Python )。 pysqlite 不支持多线程共享连接是个问题。
|
7
clino 2017-01-18 23:07:57 +08:00 via Android
gevent 并发,这样同时只有一个读写 sqlite
|
9
zwh8800 2017-01-19 10:56:43 +08:00
sqlite 并发不行的, sqlite 的事务就是锁表,你无论开几个线程,只要访问的是同一张表,最后在 sqlite 那里都会被锁,实际上最后都是顺序执行的。
正解是队列 <del>更正确的解是换数据库</del> @hosiet 重试一方面不优雅,另一方面会让性能更糟糕,堆积的重试操作多了之后,大家都抢不到锁。 |
10
tomwei7 2017-01-19 11:36:47 +08:00
加个队列吧, sqlite 不适合高并发的
|
11
gdsagdada 2017-01-19 11:50:02 +08:00
# coding:utf-8
import sqlite3 import queue, os def singleton(cls): instances = {} def _singleton(*args, **kw): if cls not in instances: instances[cls] = cls(*args, **kw) return instances[cls] return _singleton @singleton class SQLiteUtil(object): __queue_conn = queue.Queue(maxsize=1) __path = None def __init__(self, path): self.__path = path print('path:', self.__path) self.__create_conn() def __create_conn(self): conn = sqlite3.connect(self.__path, check_same_thread=False) self.__queue_conn.put(conn) def __close(self, cursor, conn): if cursor is not None: cursor.close() if conn is not None: cursor.close() self.__create_conn() def execute_query(self, sql, params): conn = self.__queue_conn.get() cursor = conn.cursor() value = None try: records = None if not params is None: records = cursor.execute(sql, params).fetchall() else: records = cursor.execute(sql).fetchall() field = [i[0] for i in cursor.description] value = [dict(zip(field, i)) for i in records] finally: self.__close(cursor, conn) return value def executescript(self, sql): conn = self.__queue_conn.get() cursor = conn.cursor() try: cursor.executescript(sql) conn.commit() except Exception as e: conn.rollback() raise finally: self.__close(cursor, conn) def execute_update(self, sql, params): return self.execute_update_many([sql], [params]) def execute_update_many(self, sql_list, params_list): conn = self.__queue_conn.get() cursor = conn.cursor() count = 0 try: for index in range(len(sql_list)): sql = sql_list[index] params = params_list[index] if not params is None: count += cursor.execute(sql, params).rowcount else: count += cursor.execute(sql).rowcount conn.commit() except Exception as e: conn.rollback() raise finally: self.__close(cursor, conn) return count ''' example: one = SQLiteUtil('xxx.sqlite') rst = one.execute_query('select * from website', None) for line in rst: print(line.get('id'), line.get('url'), line.get('content')) print(one.execute_update('update website set content = \'2222222\' where id = ?', ('1',))) print(one.execute_update('update website set content = \'2222222\' where id = \'1\'', None)) print('update many') count = one.execute_update_many( [ 'update website set content = \'一\' where id = \'1\'', 'update website set content = \'二\' where id = \'2\'', 'update website set content = 1 where id = \'3\'' ], [None, None, None] ) print('count:', count) ''' python3 的 用 py2 自己改改,可抗千万级并发[v2ex 滑稽专属表情] |
12
gdsagdada 2017-01-19 11:52:15 +08:00
楼主改 py2 了记得也贴下
|
13
Actrace 2017-01-19 13:21:28 +08:00
sqlite 是针对小型的移动设备设计的数据库。。。楼主这是准备拿 100 台手机来做服务器集群吗。。
|
14
thekoc OP |
17
gdsagdada 2017-01-19 17:06:55 +08:00
把你程序也贴出来大家观赏下[v2ex 滑稽]
|