我在python中有一个多线程应用程序,其中我创建了多个生产者线程,并从数据库中提取数据。数据以块的形式提取。因此,线程创建带有限制值的sql语句的部分将保持在锁定状态。为了让线程同时执行查询,query()函数保持在锁外。然后,结果获取部分再次保持在锁定之下。以下是代码段:
with UserAgent.lock:
sqlGeoTarget = "call sp_ax_ari_select_user_agent_list('0'," + str(self.chunkStart) + "," + str(self.chunkSize) + ",1);"
self.chunkStart += self.chunkSize
self.dbObj.query(sqlGeoTarget)
print "query executed. Processing data now..."+sqlGeoTarget
with UserAgent.lock:
result = self.dbObj.fetchAll()
self.dbObj.dbCursor.close()
但是这段代码会产生致命错误segmentation fault (core dumped)
。因为如果我将所有代码置于锁定状态,它就可以正常执行。我在获取数据后显式关闭游标,当query()函数再次触发时重新打开它。
此代码位于名为UserAgent
的类中,它是名为Producer
的类的共享资源。因此,共享数据库对象。所以问题区域99%必须是因为db对象共享同时命中查询并且关闭游标然后必须弄乱结果集。但那么如何解决这个问题并实现并发数据库查询的执行呢?
答案 0 :(得分:5)
不要跨线程重用连接。而是为每个线程创建一个新连接。
来自MySQLdb用户指南:
MySQL协议无法一次使用同一连接处理多个线程。一些早期版本的MySQLdb利用锁定来实现2的线程安全性。虽然使用标准Cursor类(使用
mysql_store_result()
)并不是很难完成,但SSCursor使用mysql_use_result()
会使其复杂化;对于后者,你必须确保在执行另一个查询之前已经读取了所有行。由于事务的添加使得事务更加复杂,因为事务在游标执行查询时开始,但在COMMIT
或{时结束{1}}由Connection对象执行。除了在查询执行期间无法共享它时,两个线程在事务正在进行时根本无法共享连接。这使得代码过于复杂到它只是不是不值得。这样做的一般结果是:不要在线程之间共享连接。这真的不值得你或我的努力,最终,可能会损害性能,因为MySQL服务器为每个连接运行一个单独的线程。您当然可以执行缓存池中的连接等操作,并一次将这些连接提供给一个线程。如果让两个线程同时使用连接,那么MySQL客户端库可能会崩溃并死掉。你被警告了。
强调我的。
改为使用thread local storage或dedicated connection pooling library。