Reputation: 501
I have the following code from a complex project:
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)
The engine is InnoDB and the output is:
0 0
1 0
Then the program hangs. I know the reason is mysql locks the row after the first greenlet executes the update statement, so the update in the other greenlet will block. But why does gevent not transfer control back to the first greenlet after the other one blocks on socket? And I wonder is there any graceful solution besides using a lock or committing before gevent.sleep
?
p.s. The original situation is in a website project. I mixed pymongo and SQLAlchemy operations and used gunicorn to serve the site. But I found that parallel requests may block forever. After a long time of debug, I finally figured out this was due to pymongo used some socket operations, which caused gevent to switch to another greenlet, resulting a deadlock as the above code demonstrates.
Thanks!
Upvotes: 1
Views: 1052
Reputation: 501
Thanks to @robertklep , one possible solution is to replace oursql
with some pure-python drivers such as pymysql
. In fact oursql
is written in C and thus incompatible with gevent
.
Upvotes: 1