如何用gevent和oursql解决死锁问题
我有一段来自复杂项目的代码:
from gevent import monkey
monkey.patch_all()
import gevent
import oursql
def run(num):
conn = oursql.connect(host = ...)
cursor = conn.cursor()
cursor.execute('start transaction')
for i in range(2):
print num, i
cursor.execute('UPDATE userobj SET timestamp=(timestamp + 1) WHERE id = 1')
gevent.sleep()
cursor.execute('rollback')
proc = [gevent.spawn(run, i) for i in range(2)]
gevent.wait(proc)
这个项目使用的数据库引擎是InnoDB,输出结果是:
0 0
1 0
然后程序就卡住了。我知道原因是mysql在第一个绿色线程执行更新语句后锁住了那一行数据,所以其他绿色线程的更新会被阻塞。但是我不明白为什么在另一个绿色线程在等待socket的时候,gevent不把控制权转回第一个绿色线程?我想知道除了使用锁或者在gevent.sleep
之前提交之外,还有没有其他好的解决办法?
补充说明: 原来的情况是在一个网站项目中。我把pymongo和SQLAlchemy的操作混在一起,并用gunicorn来提供服务。但我发现并行请求可能会永远阻塞。在经过长时间的调试后,我终于弄明白这是因为pymongo使用了一些socket操作,导致gevent切换到另一个绿色线程,最终造成了像上面代码展示的死锁。
谢谢!
1 个回答
1
感谢@robertklep,可能的解决办法是用一些纯Python的驱动程序来替代 oursql
,比如 pymysql
。实际上,oursql
是用C语言写的,所以它和 gevent
不兼容。