如何用gevent和oursql解决死锁问题

1 投票
1 回答
990 浏览
提问于 2025-04-17 19:51

我有一段来自复杂项目的代码:

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 不兼容。

撰写回答