如何在循环中使用asyncio结构安排多个任务

时间:2018-01-09 20:10:30

标签: python-3.x async-await python-3.6 python-asyncio

我的用例是运行一些性能测试,所以我想创建一个应用程序,我运行4个任务4次,计算该任务的时间平均值,然后异步运行2个任务,计算平均值,然后异步运行4个任务,计算平均值,然后是8,依此类推。

但是,我无法像这样跑。当我这样做时,它似乎已经执行过所有任务,而且我错了很多次。

我尝试了一些点击和试用版,现在我在TypeError: An asyncio.Future, a coroutine or an awaitable is required sys:1: RuntimeWarning: coroutine 'go' was never awaited函数的loop.run_until_complete(asyncio.wait(asyncio.ensure_future(some_tasks)))run_tasks获得了async def go(date): pool = await aiopg.create_pool("**db connection**") async with pool.acquire() as conn: async with conn.cursor() as cur: await cur.execute(""" some query """) time.sleep(1) ret = [] async for row in cur: ret.append(row) def date_range(date1, date2): for n in range(int((date2 - date1).days)+1): yield date1 + timedelta(n) def run_tasks(): start_dt = datetime(2017, 8, 9) end_dt = datetime(2017, 8, 10) tasks = [] some_tasks = [] avg_time_run = [] for dt in date_range(start_dt, end_dt): #tasks.append(asyncio.ensure_future(go(dt.strftime("%Y-%m-%d %H:%M:%S")))) tasks.append(go(dt.strftime("%Y-%m-%d %H:%M:%S"))) i = 1 prev = 0 while i < 2: # i < 128 # Get i number of tasks from task list for k in range(prev, i): some_tasks.append(tasks[k]) prev = len(some_tasks) time_run = [] for j in range(0, 4): # repeat task 4 times start = time.time() loop = asyncio.get_event_loop() loop.run_until_complete(asyncio.wait(asyncio.ensure_future(some_tasks))) # loop.close() end = time.time() diff = end - start time_run.append(diff) print("ith SomeTask: {}, {}".format(i, some_tasks)) print("Total time: {}".format(diff)) # get average of each task run 4 times avg_time_run.append(sum(time_run) / float(len(time_run))) i *= 2 return avg_time_run print(run_tasks())

以下是我的代码:

asyncio.wait

一些提示将不胜感激。我应该在哪里等待{{1}}

2 个答案:

答案 0 :(得分:2)

asyncio.ensure_future(some_tasks)

您将协程列表传递给asyncio.ensure_future。正如您在documentation中看到的,这不是这个函数的工作原理:您应该传递单个协同程序来创建asyncio.Task。这就是为什么你得到TypeError,然后你得到RuntimeWarning,因为创建的go协同程序不会因为以上所有而被等待。

在这种情况下你根本不需要asyncio.Task,只需将协程列表传递给asyncio.wait

loop.run_until_complete(asyncio.wait(some_tasks))

更重要的一点是:

time.sleep(1)

你永远不应该在协同程序中执行它:它冻结你的事件循环(以及所有协同程序随处可见)。请阅读this answer,了解asyncio的工作原理。

如果你想在协同程序中睡一段时间,请使用asyncio.sleep

await asyncio.sleep(1)

答案 1 :(得分:0)

回答代码:

async def run(date): // for adopt, check above go() function
    conn = await asyncpg.connect("db connections")
    values = await conn.fetch("""some query """)
    await asyncio.sleep(1)
    await conn.close()


def date_range(date1, date2):
    for n in range(int((date2 - date1).days)+1):
        yield date1 + timedelta(n)


def run_tasks():

    start_dt = datetime(2017, 8, 9)
    end_dt = datetime(2017, 8, 10)

    tasks = []

    avg_time_run = []

    i = 1

    while i < 9:  # num of tasks incremented
        time_run = []

        start = time.time()
        loop = asyncio.get_event_loop()

        for dt in date_range(start_dt, end_dt):
            if len(tasks) < i:
                print(dt)
                tasks.append(asyncio.ensure_future(run(dt.strftime("%Y-%m-%d %H:%M:%S"))))

                if len(tasks) == i:

                    for j in range(0, 4):  # repeat task 4 times
                        print("J counter: {}".format(j))

                        loop.run_until_complete(asyncio.wait(tasks))

                        end = time.time()
                        diff = end - start
                        time_run.append(diff)
                        print("Num of Tasks executing: {}, {}".format(i, tasks))
                        print("Task len: {}".format(len(tasks)))
                        print("Total time: {}".format(diff))

        # get average of each task run 4 times
        avg_time_run.append(sum(time_run) / float(len(time_run)))
        start_dt = end_dt + timedelta(days=1)
        end_dt = end_dt + timedelta(days=(i * 2 - i))
        i *= 2

        print(start_dt)
        print(end_dt)
        #loop.close()

    return avg_time_run


print(run_tasks())