<div dir="ltr"><div class="gmail_quote">On Tue, 12 May 2015 at 05:08 Mike Bayer <<a href="mailto:mbayer@redhat.com">mbayer@redhat.com</a>> wrote:<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
On 5/11/15 2:02 PM, Attila Fazekas wrote:<br>
> The scary part of a blocking I/O call is when you have two<br>
> python thread (or green thread) and one of them is holding a DB lock the other<br>
> is waiting for the same lock in a native blocking I/O syscall.<br>
that's a database deadlock and whether you use eventlet, threads,<br>
asycnio or even just two transactions in a single-threaded script, that<br>
can happen regardless.  if your two eventlet "non blocking" greenlets<br>
are waiting forever for a deadlock,  you're just as deadlocked as if you<br>
have OS threads.<br></blockquote><div><br></div><div>Not true (if I understand the situation Attila is referring to).</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
> If you do a read(2) in native code, the python itself might not be able to preempt it<br>
> Your transaction might be finished with `DB Lock wait timeout`,<br>
> with 30 sec of doing nothing, instead of scheduling to the another python thread,<br>
> which would be able to release the lock.<br>
<br>
<br>
Here's the "you're losing me" part because Python threads are OS<br>
threads, so Python isn't directly involved trying to "preempt" anything,<br>
unless you're referring to the effect of the GIL locking up the<br>
program.   However, it's pretty easy to make two threads in Python hit a<br>
database and do a deadlock against each other, and the rest of the<br>
program's threads continue to run just fine; in a DB deadlock situation<br>
you are blocked on IO and IO releases the GIL.<br>
<br>
If you can illustrate a test script that demonstrates the actual failing<br>
of OS threads that does not occur greenlets here, that would make it<br>
immediately apparent what it is you're getting at here.<br></blockquote><div><br></div><div>1. Thread A does something that takes a lock on the DB side</div><div>2. Thread B does something that blocks waiting for that same DB lock</div><div>3. Depends on the threading model - see below</div><div><br></div><div>In a "true" preemptive threading system (eg: regular python threads), (3) is:</div><div><br></div><div>3.  Eventually A finishes its transaction/whatever, commits and releases the DB lock</div><div>4. B then takes the lock and proceeds</div><div>5. Profit</div><div><br></div><div>However, in a system where B's DB client can't be preempted (eg: eventlet or asyncio calling into a C-based mysql library, and A and B are running on the same underlying kernel thread), (3) is:</div><div><br></div><div>3. B will never be preempted, A will never be rescheduled, and thus A will never complete whatever it was doing.</div><div>4. Deadlock (in mysql-python's case, until a deadlock timer raises an exception and kills B 30s later)</div><div>5. Sadness.  More specifically, we add a @retry to paper over the particular observed occurrence and then repeat this discussion on os-dev when the topic comes up again 6 months later.</div><div><br></div><div>Note that this is not the usual database transaction deadlock caused by A and B each taking a lock and then trying to take the other's lock - this is a deadlock purely in the client-side code caused entirely by the lack of preemption during an otherwise safe series of DB operations.</div><div><br></div><div>See my oslo.db unittest in Ib35c95defea8ace5b456af28801659f2ba67eb96 that reproduces the above with eventlet and allows you to test the behaviour of various DB drivers.</div><div><br></div><div>(zzzeek: I know you've already seen all of the above in previous discussions, so sorry for repeating).</div><div><br></div><div> - Gus</div></div></div>