Question about asyncio and blocking operations

Ian Kelly ian.g.kelly at gmail.com
Thu Jan 28 10:33:17 EST 2016


On Jan 28, 2016 4:13 AM, "Frank Millman" <frank at chagford.com> wrote:
>
> "Chris Angelico"  wrote in message
news:CAPTjJmr162+K4LZeFpXruR6wxrHxbR-_wkrCLLDyR7kST+kjYg at mail.gmail.com...
>>
>>
>> On Thu, Jan 28, 2016 at 8:13 PM, Frank Millman <frank at chagford.com>
wrote:
>> > Run the database handler in a separate thread. Use a queue.Queue to
send
>> > requests to the handler. Use an asyncio.Queue to send results back to
> the
>> > caller, which can call 'await q.get()'.
>> >
>> > I ran a quick test and it seems to work. What do you think?
>>
>> My gut feeling is that any queue can block at either get or put ....
>>
>
> H'mm, I will have to think about that one, and figure out how to create a
worst-case scenario. I will report back on that.

The get and put methods of asyncio queues are coroutines, so I don't think
this would be a real issue. The coroutine might block, but it won't block
the event loop. If the queue fills up, then effectively the waiting
coroutines just become a (possibly unordered) extension of the queue.

>>
>> The other risk is that the wrong result will be queried (two async
>> tasks put something onto the queue - which one gets the first
>> result?), which could either be coped with by simple sequencing (maybe
>> this happens automatically, although I'd prefer a
>> mathematically-provable result to "it seems to work"), or by wrapping
>> the whole thing up in a function/class.
>>
>
> I *think* I have this one covered. When the caller makes a request, it
creates an instance of an asyncio.Queue, and includes it with the request.
The db handler uses this queue to send the result back.
>
> Do you see any problem with this?

That seems reasonable to me. I assume that when you send the result back
you would be queuing up individual rows and not just sending a single
object across, which could be more easily with just a single future.

The main risk of adding limited threads to an asyncio program is that
threads make it harder to reason about concurrency. Just make sure the
threads don't share any state and you should be good.

Note that I can only see queues being used to move data in this direction,
not in the opposite. It's unclear to me how queue.get would work from the
blocking thread. Asyncio queues aren't threadsafe, but you couldn't just
use call_soon_threadsafe since the result is important. You might want to
use a queue.Queue instead in that case, but then you run back into the
problem of queue.put being a blocking operation.



More information about the Python-list mailing list