Squeak.ru - шаблоны программирования

Как правильно вызывать асинхронный код в обычном обратном вызове?

Как правильно вызывать асинхронный код в обычном обратном вызове? Этот код работает, но выглядит некрасиво. Мне не нравится, как вызывается ответ: ему нужно передать адрес вызывающего абонента через все функции. Как установить тайм-аут для обработчика?

Я размещал вопросы в комментариях.

import asyncio
import logging
logger = logging.getLogger('protocol')

async def echo(data):
    #external lib emulator
    data = b'>'+data
    await asyncio.sleep(1)
    return data


class Protocol(asyncio.DatagramProtocol):
    def connection_made(self, transport):
        logger.debug('connection_made called')
        self.transport = transport

    def respond(self,task):
        logger.debug('respond called')
        # i want to get data in attrs, not task

        resp,caller = task.result()

        self.transport.sendto(resp, caller)


    async def handler(self,data, caller):
        logger.debug('handler called')

        # async needed for `await` and `async for` external library such motor, etc
        # do some awaits
        data = await echo(data)

        # simple echo
        return (data, caller)


    def datagram_received(self, data, addr):
        logger.debug('datagram_received called')

        # handler selected by data header
        handler = self.handler

        # how to do run async handler?
        loop = asyncio.get_event_loop()
        c = handler(data, addr) #coroutine

        f = asyncio.ensure_future(c,loop=loop) #attach coroutine to loop
        f.add_done_callback(self.respond)

        # How to get response here?

        # i cant loop.run_until_complete(...) because loop.run_forever() running

        #def wakeup():
        #    pass
        #loop.call_soon(wakeup)
        # without this call_soon future is not executed in first programm code, but works in test and after refactor


def main(HOST,PORT):

    loop = asyncio.get_event_loop()
    t = asyncio.Task(loop.create_datagram_endpoint(
        Protocol, local_addr=(HOST,PORT)))
    transport, server = loop.run_until_complete(t)

    sock = transport.get_extra_info('socket')
    # socket tuning here

    try:
        loop.run_forever()
    finally:
        transport.close()
        loop.close()

logging.basicConfig(level=logging.DEBUG)     
main('0.0.0.0',10012)

Используйте netcat для проверки nc -u 127.0.0.1 10012


  • Я думаю, вы правы: asyncio.ensure_future это правильный путь. 25.10.2016
  • @SergeyBelash, как получить от него данные на месте (без обратного вызова)? 25.10.2016
  • ensure_future запускается только после возврата datagram_received 25.10.2016
  • Нижний уровень asyncio основан на обратных вызовах, а asyncio не предоставляет объекты на основе сопрограмм для UDP. Однако вы можете взглянуть на конечные точки UDP высокого уровня для asyncio, это может дать у вас есть некоторое представление о том, как реализовать аналогичные решения на основе сопрограмм. 25.10.2016

Ответы:


1

Вы можете использовать asyncio.Queue для размещения задач в одной сопрограмме (обработчик) и await их в другой (ответ):

class Protocol(asyncio.DatagramProtocol):

    def __init__(self):
        self.data_queue = asyncio.Queue(loop=asyncio.get_event_loop())
        asyncio.ensure_future(self.respond())

    def connection_made(self, transport):
        self.transport = transport

    def datagram_received(self, data, addr):
        asyncio.ensure_future(self.handler(data, addr), loop=asyncio.get_event_loop())

    async def respond(self):
        while True:
            resp, caller = await self.data_queue.get()
            self.transport.sendto(resp, caller)

    async def handler(self, data, caller):
        data = await echo(data)
        self.data_queue.put((data, caller))
25.10.2016
  • self.data_queue.get() блокирует цикл? 25.10.2016
  • @eri нет, этот метод является coroutine docs.python .org/3/library/asyncio-queue.html#asyncio.Queue.get 26.10.2016

  • 2

    Лучший способ, который я нашел, - это создать задачу для каждой дейтаграммы с помощью асинхронной функции.

    class Protocol(AbstractProtocol):
    
        async def datagram_received_async(self, data, addr):
            await a()
            await b()
    
        def datagram_received(self, data, addr):
            self.loop.create_task(self.datagram_received_async( data, addr))
    

    У фьючерсов есть нежданные предупреждения. Задачи ок. Очередь в этом случае не нужна.

    01.12.2020
  • есть ли способ синхронно дождаться результата async def в datagram_received? 19.03.2021
  • datagram_received не имеет возврата, поэтому синхронное ожидание не делает ничего полезного. 20.03.2021
  • Новые материалы

    Угловая структура архитектуры
    Обратите внимание, что эта статья устарела, я решил создать новую с лучшей структурой и с учетом автономных компонентов: https://medium.com/@marekpanti/angular-standalone-architecture-b645edd0d54a..

    «Данные, которые большинство людей используют для обучения своих моделей искусственного интеллекта, поставляются со встроенным…
    Первоначально опубликовано HalkTalks: https://hacktown.com.br/blog/blog/os-dados-que-a-maioria-das-pessoas-usa-para-treinar-seus-modelos-de-inteligencia-artificial- ja-vem-com-um-vies-embutido/..

    Сильный ИИ против слабого ИИ: различия парадигм искусственного интеллекта
    В последние годы изучению и развитию искусственного интеллекта (ИИ) уделяется большое внимание и прогресс. Сильный ИИ и Слабый ИИ — две основные парадигмы в области искусственного интеллекта...

    Правильный способ добавить Firebase в ваш проект React с помощью React Hooks
    React + Firebase - это мощная комбинация для быстрого и безопасного создания приложений, от проверки концепции до массового производства. Раньше (знаете, несколько месяцев назад) добавление..

    Создайте API с помощью Python FastAPI
    Создание API с помощью Python становится очень простым при использовании пакета FastAPI. После установки и импорта вы можете создать приложение FastAPI и указать несколько конечных точек. Каждой..

    Веселье с прокси-сервером JavaScript
    Прокси-серверы JavaScript — это чистый сахар, если вы хотите создать некоторую общую логику в своих приложениях, чтобы облегчить себе жизнь. Вот один пример: Связь клиент-сервер Мы..

    Получить бесплатный хостинг для разработчиков | Разместите свой сайт за несколько шагов 🔥
    Статические веб-сайты — это веб-страницы с фиксированным содержанием и его постоянным содержанием. Но теперь статические сайты также обрабатывают динамические данные с помощью API и запросов...