sqlite3 多线程高并发的访问如何处理?

2017-01-18 22:27:51 +08:00
 thekoc

用得是自带的 sqlite3 库,可能有 100 个左右的线程吧,目前是每个线程拥有一个单独的连接,所有连接的插入间隔大约是 0.00x 秒,会出现 datebase is locked 错误,请问怎么处理呢?

17747 次点击
所在节点    Python
18 条回复
mansur
2017-01-18 22:32:31 +08:00
弄一个队列写吧
murmur
2017-01-18 22:55:55 +08:00
我怎么印象中 sqlite 用排队+锁的机制比多线程还要好一点
100 线程的话为啥不考虑 mysql 啊
hosiet
2017-01-18 22:57:40 +08:00
写入发现被锁了就循环多试几次嘛,可以给个重试上限(例如五次,或者没上限也行)以及重试时间间隔等等。

不过我记得好像有阻塞的写法吧,就是完成写入才返回那种。不知道你用的是什么编程语言?
thekoc
2017-01-18 22:59:26 +08:00
@murmur 因为想尽量用标准库完成。。
thekoc
2017-01-18 22:59:43 +08:00
@hosiet Python
hosiet
2017-01-18 23:02:18 +08:00
糟糕没看节点( Python )。 pysqlite 不支持多线程共享连接是个问题。
clino
2017-01-18 23:07:57 +08:00
gevent 并发,这样同时只有一个读写 sqlite
thekoc
2017-01-18 23:09:29 +08:00
@hosiet 是支持的,要开启一个选项
zwh8800
2017-01-19 10:56:43 +08:00
sqlite 并发不行的, sqlite 的事务就是锁表,你无论开几个线程,只要访问的是同一张表,最后在 sqlite 那里都会被锁,实际上最后都是顺序执行的。

正解是队列

<del>更正确的解是换数据库</del>

@hosiet 重试一方面不优雅,另一方面会让性能更糟糕,堆积的重试操作多了之后,大家都抢不到锁。
tomwei7
2017-01-19 11:36:47 +08:00
加个队列吧, sqlite 不适合高并发的
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 滑稽专属表情]
gdsagdada
2017-01-19 11:52:15 +08:00
楼主改 py2 了记得也贴下
Actrace
2017-01-19 13:21:28 +08:00
sqlite 是针对小型的移动设备设计的数据库。。。楼主这是准备拿 100 台手机来做服务器集群吗。。
thekoc
2017-01-19 14:59:02 +08:00
thekoc
2017-01-19 15:00:06 +08:00
@gdsagdada 我发现我插入数据的平均速度是要大于这种写法的插入速度的……所以最后会导致内存爆炸
gdsagdada
2017-01-19 17:06:29 +08:00
@thekoc 内存爆了找你程序内存爆的原因,不报: datebase is locked 错误说明并发解决了
gdsagdada
2017-01-19 17:06:55 +08:00
把你程序也贴出来大家观赏下[v2ex 滑稽]
thekoc
2017-01-19 17:45:02 +08:00
@gdsagdada 我还没有试,我的意思是说我的平均插入速度要大于用这个方式做出来的函数的最高插入速度……所以无论如何还是会阻塞的。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/335488

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX