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

时间:2013-03-21 09:56:22

标签: python deadlock 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在第一个greenlet执行update语句后锁定了行,因此其他greenlet中的更新将被阻塞。但是为什么gevent不会在另一个阻塞插座后将控制权转移回第一个greenlet?我想知道除gevent.sleep之前使用锁或提交之外还有什么优雅的解决方案吗?

P.S。 最初的情况是在一个网站项目中。我混合了pymongo和SQLAlchemy操作,并使用gunicorn为该网站提供服务。但我发现并行请求可能永远阻止。经过长时间的调试,我终于弄清楚这是因为pymongo使用了一些套接字操作,导致gevent切换到另一个greenlet,导致死锁,如上面的代码所示。

谢谢!

1 个答案:

答案 0 :(得分:1)

感谢@robertklep,一个可能的解决方案是将oursql替换为pymysql等纯python驱动程序。实际上oursql是用C语言编写的,因此与gevent不兼容。