我在 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% 一定是因为数据库对象是共享的,同时点击查询并关闭游标,那么一定会弄乱结果集。那么如何解决这个问题并实现并发数据库查询执行呢?
不要跨线程重用连接。相反,为每个线程创建一个新连接。
来自 MySQLdb 用户指南:
MySQL 协议无法同时处理使用同一连接的多个线程。 MySQLdb 的一些早期版本利用锁定来实现 2 的线程安全性。虽然使用标准 Cursor 类(它使用mysql_store_result()
),SSCursor(它使用mysql_use_result()
;对于后者,您必须确保在执行另一个查询之前已读取所有行。添加事务使情况变得更加复杂,因为事务在游标执行查询时开始,但在游标执行查询时结束COMMIT
or ROLLBACK
由Connection对象执行。除了在查询执行期间无法共享连接之外,两个线程在事务正在进行时根本无法共享连接。这使得代码过于复杂,以至于不值得。
总体结果是:不要在线程之间共享连接。这确实不值得你或我的努力,并且最终可能会损害性能,因为 MySQL 服务器为每个连接运行一个单独的线程。您当然可以执行诸如在池中缓存连接之类的操作,并一次将这些连接提供给一个线程。如果你让两个线程同时使用一个连接,MySQL 客户端库可能会崩溃并死掉。你被警告了。
强调我的。
Use 线程本地存储 or a 专用连接池库反而。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)