0 mysql multithreading multiprocessing python-3.x
在提出这个问题之前,我已经搜索了很多关于“跨线程共享相同的数据库连接”的信息。我得到的大多数答案是否定的,并使用连接池代替,但很少有人详细解释为什么我们不能这样做。
然后我使用多处理和多线程编写了一个示例代码,我试图弄清楚它,但仍然有一些困难需要解决。这是我得到的:
多重处理:
import multiprocessing as multiprocessing
import pymysql
conn = pymysql.connect(host='localhost', port=3306, user='root', passwd='123456', db='test')
def operate(sql):
cur = conn.cursor()
cur.execute(sql)
cur.close()
return cur.fetchall()
pool = multiprocessing.Pool(4)
res = []
for seq in range(1, 3):
sql = "SELECT * FROM `user` WHERE `id` = %d" % seq
p = pool.apply_async(operate, [sql, ])
res.append(p)
pool.close()
pool.join()
conn.close()
for j in res:
print(j.get())
Run Code Online (Sandbox Code Playgroud)
正如预期的那样,这段代码无法正常工作:
((None, None, 1, 'ttt', 'hhh', 1, 0, ''),) # process1
((None, None, 2, 'zzz', '1256', 1, 0, ''),) # process2 (1), this is normal output and should be what we want.
Run Code Online (Sandbox Code Playgroud)
((None, None, 2, 'zzz', '1256', 1, 0, ''),)
((None, None, 1, 'ttt', 'hhh', 1, 0, ''),) # (2), this is incorrect output.
Run Code Online (Sandbox Code Playgroud)
跑了很多次,要么得到(1),要么得到(2)。原因(我认为)是:虽然多处理并行运行,但 process1 仍然早于 process2 被调用。对于mysql来说,哪个进程的查询先完成是不确定的。如果 process2 提前完成,因为它们共享相同的连接,连接按照调用的顺序返回数据,所以我得到情况(2),否则情况(1)。我对吗?
多线程
import multiprocessing.dummy as multithread
import pymysql
from queue import Queue
conn = pymysql.connect(host='localhost', port=3306, user='root', passwd='123456', db='test')
def operate(sql):
cur = conn.cursor()
cur.execute(sql)
cur.close()
res.put(cur.fetchall())
pool = multithread.Pool(4)
res = Queue()
for seq in range(1, 3):
sql = "SELECT * FROM `user` WHERE `id` = %d" % seq
p = pool.apply_async(operate, [sql, ])
pool.close()
pool.join()
conn.close()
print(res.get())
Run Code Online (Sandbox Code Playgroud)
最初我认为这段代码的结果与多处理相同,但结果不同。它打印了 process1 或 process2,甚至卡在那里。为什么?
将 db 隔离级别更改为 SERIALIZABLE 可以解决此问题吗?
我试过。对于多处理来说,这似乎可行;但对多线程没有影响。理论上应该可行,不是吗?如果是这样,我无论如何都不会这么做,只是想办法解决。
当您的 python 程序使用多个线程内的单个conn对象时,它会混合来自单个数据库连接上的多个线程的消息流量(线程 <==> MySql)。那行不通™。
MySQL 连接对象不是线程安全的。每个需要访问 MySQL 的线程必须打开自己的连接。(MySQL 连接池对象是线程安全的,因此每个线程都可以安全地请求、使用和释放池中的连接。)
专家提示:当复杂的长期软件(如pymysql)的开发人员告诉您它不是线程安全的时,请相信他们。
| 归档时间: |
|
| 查看次数: |
1954 次 |
| 最近记录: |