broomrider
broomrider

Reputation: 656

asyncio.queue strange behaviour

This code

import asyncio


@asyncio.coroutine
def foo(q):

    print("foo before", q.empty())
    q.put_nowait("yoba")
    print("foo after", q.empty())


@asyncio.coroutine
def bar(q):

    for _ in range(5):

        asyncio.async(foo(q))
        r = yield from q.get()
        print("bar received", r)


q = asyncio.Queue()
asyncio.get_event_loop().run_until_complete(bar(q))

Produce this output:

foo before True
foo after True
bar received yoba
foo before True
foo after True
bar received yoba
foo before True
foo after True
bar received yoba
foo before True
foo after True
bar received yoba
foo before True
foo after True
bar received yoba

Why queue become empty, even when I did not yield from and flow control did not return to loop? I expect, that elements will not "pop" from queue until I will return flow control to loop and it decide to "pop" data.

Upvotes: 1

Views: 642

Answers (1)

Huazuo Gao
Huazuo Gao

Reputation: 1733

In the source of asyncio.Queue.put_nowait:

if self._getters:
    assert not self._queue, (
        'queue non-empty, why are getters waiting?')

    getter = self._getters.popleft()
    self.__put_internal(item)

    # getter cannot be cancelled, we just removed done getters
    getter.set_result(self._get())

As we can see, if at least one get() is not fulfilled, any call to put_nowait() will put an item into the queue, then pop it immediately, giving no chance for the queue to be in a nonempty state.

Upvotes: 3

Related Questions