简体   繁体   中英

why asyncio.queue get faild?

Python3, asyncio Task A is putting a number to a queue every 2s, task B is wait for the queue.get() with timeout 1s in a forever loop.

I don't know why can't get the number from the queue in task B, if timeout is bigger than 2s, queue.get() is ok.

import asyncio


class Test:
    def __init__(self, loop=None):
        self._queue = asyncio.Queue(loop=loop)
        self._future = asyncio.Future(loop=loop)

    @asyncio.coroutine
    def run(self):
        asyncio.async(self._feed_queue(2))
        asyncio.async(self._recv())
        # yield from asyncio.sleep(10.0)
        # self._future.set_exception('Fail')

    @asyncio.coroutine
    def _feed_queue(self, interval):
        v = 0
        while True:
            yield from asyncio.sleep(interval)
            print("feed")
            yield from self._queue.put(v)
            v = v+1


    @asyncio.coroutine
    def _recv(self):
        while True:
            try:
                print('wait')
                # r = yield from asyncio.wait([self._queue.get(), self._future], return_when=asyncio.FIRST_COMPLETED, timeout=1.0)
                # for x in r[0]:
                #     if x.exception():
                #         raise x.exception()
                #     print("recv", x.result())

                try:
                    r = yield from asyncio.wait_for(self._queue.get(), timeout=1.0)
                    print(r)
                except:
                    continue
                # print("recv", r)
                # in done set
            except BaseException as e:
                print(e)
                break

        print("quit")


loop = asyncio.get_event_loop()
t = Test(loop=loop)
asyncio.async(t.run())
loop.run_forever()

output:

wait
wait
feed
wait
wait
feed
wait
wait
feed
wait

The first call to self._queue.get() may return the value, but it is not used, and new call is made.

Adjusted to use the call (and to use asyncio.ensure_future ; otherwise, AssertionError("yield from wasn't used with future",) is raised)

@asyncio.coroutine
def _recv(self):
    future = None
    while True:
        try:
            if future is None:
                future = asyncio.ensure_future(self._queue.get())
            r = yield from asyncio.wait(
                [future, self._future],
                return_when=asyncio.FIRST_COMPLETED,
                timeout=1.0
            )
            for x in r[0]:
                if x.exception():
                    raise x.exception()
                if x is future:
                    future = None
                print("recv", x.result())
        except BaseException as e:
            print(e)
            break

    print("quit")

used asyncio.ensure_future instead of asyncio.async because later one is deprecated.

It is ok on Python-3.5.1.

asyncio.Queue was re-written

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM