具有asyncio和aiohttp

时间:2018-06-28 09:05:58

标签: python-3.x python-asyncio aiohttp

我试图了解如何最好地执行以下操作:

考虑多个分析。每个分析都从多个数据源(REST API)请求数据。在每次分析中,当从数据源收集了所有数据时,将检查数据是否存在一个或多个条件。如果满足这些条件,则会向另一个数据源发出另一个请求。

目标是异步收集所有分析的数据,检查每个分析的条件,要求条件是否满足,然后重复。因此,需要满足以下条件:

  1. 在特定分析中收集所有数据后,检查数据是否符合条件,而不是在所有分析中收集数据之后。
  2. 如果满足条件,则首先发出请求-在检查完所有分析的条件之后才进行请求。
  3. 获取数据->检查条件->可能要求计划每X分钟或每小时运行一次循环。

我进行了以下演示:

import asyncio
import random


async def get_data(list_of_data_calls):
    tasks = []
    for l in list_of_data_calls:
        tasks.append(asyncio.ensure_future(custom_sleep(l)))
    return await asyncio.gather(*tasks)


async def custom_sleep(time):
    await asyncio.sleep(time)
    return random.randint(0, 100)


async def analysis1_wrapper():
    while True:
        print("Getting data for analysis 1")
        res = await get_data([5, 3])
        print("Data collected for analysis 1")
        for integer in res:
            if integer > 80:
                print("Condition analysis 1 met")
            else:
                print("Condition analysis 1 not met")
        await asyncio.sleep(10)


async def analysis2_wrapper():
    while True:
        print("Getting data for analysis 2")
        res = await get_data([5, 3])
        print("Data collected for analysis 2")
        for integer in res:
            if integer > 50:
                print("Condition analysis 2 met")
            else:
                print("Condition analysis 2 not met")
        await asyncio.sleep(10)


loop = asyncio.get_event_loop()
tasks = analysis1_wrapper(), analysis2_wrapper()
loop.run_until_complete(asyncio.gather(*tasks))
loop.close()

这将产生以下输出:

Getting data for analysis 2
Getting data for analysis 1
Data collected for analysis 2
Condition analysis 2 not met
Condition analysis 2 not met
Data collected for analysis 1
Condition analysis 1 not met
Condition analysis 1 not met
Getting data for analysis 2
Getting data for analysis 1
Data collected for analysis 2
Condition analysis 2 met
Condition analysis 2 not met
Data collected for analysis 1
Condition analysis 1 not met
Condition analysis 1 not met
Getting data for analysis 2
Getting data for analysis 1
Data collected for analysis 2
Condition analysis 2 not met
Condition analysis 2 not met
Data collected for analysis 1
Condition analysis 1 not met
Condition analysis 1 not met

这似乎可以按我的意愿工作。但是,由于我对asyncio和aiohttp的经验有限,因此我不确定这是否是一个好方法。我希望将来能够在管道中添加步骤,例如如果满足条件,则基于围绕发出的请求的逻辑进行操作。此外,它应该可扩展到许多分析,而不会损失太多速度。

1 个答案:

答案 0 :(得分:1)

是的,基本上就是这样。需要考虑的几件事:

  1. 并发限制。

尽管您可能有无限数量的并发任务,但是随着并发性的增长,每个任务的响应时间也会增长,吞吐量有时会停止增长甚至下降。因为只有一个主线程可以执行所有操作,所以即使网络响应是在几毫秒前到达的,回调也必须在队列过多时排队。为了平衡这一点,通常需要使用Semaphore来控制最大并发性能。

  1. CPU密集型操作。

您的代码未显示,但担心的是条件检查可能会占用大量CPU。在这种情况下,您应该将任务推迟到thread pool(没有GIL问题)或子进程(如果GIL是问题)中,其原因有两个:1.阻止阻塞的主线程损害并发性。 2.更有效地利用多个CPU。

  1. 任务控制。

您的当前代码在每次分析中循环休眠10秒。这使得很难正常关闭分析仪,更不用说动态扩展了。理想的模型应该是producer-consumer模式,在该模式中,您可以将具有某种控制权的任务生成到Queue中,然后一堆工作人员从队列中检索任务并同时进行处理。