[issue23812] asyncio.Queue.put_nowait(), followed get() task cancellation leads to item being lost

Gustavo J. A. M. Carneiro report at bugs.python.org
Thu Aug 6 22:42:32 CEST 2015


Gustavo J. A. M. Carneiro added the comment:

I don't think the order for multiple concurrent getters matters that much.  With analogy with the threading case, if multiple threads are blocked get()ing an item from the same queue, I would not presume to expect anything about the ordering which thread receives which item.

That being said, I'm sorry patch caused this problem, but losing items is an infinitely worse problem.

That being said, I think the problem stems from the way queue get is designed.  Currently it is something like:

1. get(): in case the queue is empty, create a Future, add it to "_getters", then begin waiting for this future;
2. When an item is being put(), take the first getter and set its result to the item being put;
3. the get() coroutine resumes and the item is found in the futures's result.

A better design is to make it so the future that get() is waiting for doesn't actually receive the item, it is only used to "wake up" the get() coroutine.  I would be something like:

1. get(): in case the queue is empty, create a Future, add it to "_getters", then begin waiting for this future;
2. When an item is being put():
   2.1. add the item to the internal queue
   2.2. take the first getter and set its result to None
3. the get() coroutine resumes, and then takes an item from the internal queue, returning it.

Clearly, in this design, handling cancellation in get is much simpler: you don't need to do anything, just let it cancel, no cleanup action needed.

----------

_______________________________________
Python tracker <report at bugs.python.org>
<http://bugs.python.org/issue23812>
_______________________________________


More information about the Python-bugs-list mailing list