2

我在 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 对象是共享的同时命中查询和关闭游标然后必须弄乱结果集。但是那么如何解决这个问题并实现并发的db查询执行呢?

4

1 回答 1

7

不要跨线程重用连接。而是为每个线程创建一个新连接。

来自 MySQLdb 用户指南:

MySQL 协议不能同时使用同一个连接处理多个线程。一些早期版本的 MySQLdb 利用锁定来实现 2 的线程安全性。虽然使用标准 Cursor 类(使用mysql_store_result())实现这一点并不难,但 SSCursor (使用mysql_use_result(); 使用后者你必须确保所有行在执行另一个查询之前已经读取了。添加事务使情况更加复杂,因为事务在游标执行查询时开始,但在COMMIT或时结束ROLLBACK由 Connection 对象执行。除了在查询执行期间无法共享之外,两个线程在事务进行时根本无法共享连接。这使代码过于复杂,以至于不值得。

这样做的一般结果是:不要在线程之间共享连接。这真的不值得你或我的努力,最终可能会损害性能,因为 MySQL 服务器为每个连接运行一个单独的线程。您当然可以做一些事情,例如在池中缓存连接,并一次将这些连接提供给一个线程。如果你让两个线程同时使用一个连接,MySQL 客户端库可能会崩溃并死掉。你被警告了。

强调我的。

请改用线程本地存储专用连接池库

于 2012-11-28T11:57:40.527 回答