Сделайте асинхронный c HTTP-запрос и продолжите выполнение цикла - PullRequest
0 голосов
/ 09 июля 2020

У меня есть простая функция python со следующим псевдокодом:

while True:

    # 1 - CPU Intensive calculations(Synchronous)
    
    
    # 2 - Take the result from the synchronous calculation and POST it to a server

while l oop работает вечно и выполняет вычисления с интенсивным использованием ЦП для первой половины l oop . Все это выполняется синхронно, и это нормально. Я бы хотел сэкономить время, сделав запрос POST асинхронным. В то время как l oop должен выполняться вечно, однако я бы хотел, чтобы запрос выполнялся асинхронно, чтобы l oop мог продолжить следующую итерацию, не дожидаясь разрешения запроса.

Будет хотел бы знать, как лучше всего достичь этого с помощью asyncio без использования каких-либо дополнительных потоков / гринлетов / процессов

Edit

Перед тем, как разместить здесь вопрос, я попробовал этот подход:

async def example_function():
    # Synchronous CPU Intensive calculations

    client = httpx.AsyncClient()
    # Make a call to the REST API
    await client.post()


async def main():
    while True:
        await asyncio.gather(example_function(), example_function())


if __name__ == "__main__":
    asyncio.run(main())

Я совершенно не знаком с асинхронным программированием с python. Я попробовал метод сбора, однако недостаток моего подхода к реализации заключается в том, что вторая итерация example_function () не выполняет запрос POST асинхронно. Я понимаю, что asyncio.gather () в основном планирует задачу для каждой из переданных ему функций, и если одна из задач ожидает, она продолжает выполнение следующей. Однако мне нужно запускать example_function () в al oop навсегда, а не только n раз

1 Ответ

1 голос
/ 09 июля 2020

Хотел бы знать, как лучше всего добиться этого с помощью asyncio без использования каких-либо дополнительных потоков / гринлетов / процессов

Если ваш код синхронный, вам нужно будет использовать некоторая форма многопоточности, но вы можете сделать это чисто через пул потоков, предоставленный asyncio для этой цели. Например, если вы запустите свой код syn c через loop.run_in_executor(), событие l oop будет продолжать вращаться, пока выполняются вычисления, и задачи, помещенные в фоновый режим, будут обслуживаться. Это позволяет использовать asyncio.create_task() для запуска второй части l oop в фоновом режиме или, точнее, параллельно с остальной частью события l oop.

def calculations(arg1):
    # ... synchronous code here

async def post_result(result, session):
    async with session.post('http://httpbin.org/post',
                            data={'key1': result}) as resp:
        resp.raise_for_status()

async def main():
    loop = asyncio.get_event_loop()

    with aiohttp.ClientSession() as session:
        while True:
            # run the sync code off-thread so the event loop
            # continues running, but wait for it to finish
            result = await loop.run_in_executor(None, calculations, arg1)

            # don't await the task, let it run in the background
            asyncio.create_task(post_result(result, session))

if __name__ == '__main__':
    asyncio.run(main())
...