asyncio Queue.get delay

1

У меня есть следующий код:

import asyncio
import threading
import time

q = asyncio.Queue()

async def ping():
    while True:
        await asyncio.sleep(10)
        print("ping")

async def rcv():
    while True:
        item = await q.get()
        print("got item")

async def run():
    tasks = [asyncio.ensure_future(ping()), asyncio.ensure_future(rcv())]
    await asyncio.wait(tasks, return_when="FIRST_EXCEPTION")

loop = asyncio.get_event_loop()

def run_loop():
    asyncio.set_event_loop(loop)
    loop.run_until_complete(run())

threading.Thread(target=run_loop).start()

while True:
    time.sleep(2)
    q.put_nowait("item")
    print("item added")

Я ожидал, что каждые 2 секунды (каждый раз, когда элемент добавляется в очередь), я увижу вывод:

item added
sleeping 2 seconds
got item

и каждые 10 секунд я также увижу ping.

Тем не менее, это вывод, который я получаю (повторяя):

sleeping 2 seconds
item added
sleeping 2 seconds
item added
sleeping 2 seconds
item added
sleeping 2 seconds
item added
sleeping 2 seconds
got item
got item
got item
got item
ping
item added
sleeping 2 seconds
...

Кажется, что часть item = await q.get() также asyncio.sleep(10) из функции ping.

Что я упустил? и как я могу исправить код, чтобы получить ожидаемый результат?

Спасибо!

Теги:
python-3.x
python-asyncio
queue

1 ответ

1
Лучший ответ

Что я упустил? и как я могу исправить код, чтобы получить ожидаемый результат?

Поскольку вы запускаете цикл событий в отдельном потоке, вам необходимо изменить q.put_nowait("item") на:

loop.call_soon_threadsafe(q.put_nowait, "item")

Причина в том, что асинхронный код (намеренно) не является потокобезопасным, поэтому использование put_nowait не уведомляет цикл событий о том, что новый элемент был установлен в очередь.

  • 0
    Оно работает. Спасибо!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню