Python 3.x 如何在循环中使用asyncio构造安排多个任务

Python 3.x 如何在循环中使用asyncio构造安排多个任务,python-3.x,async-await,python-3.6,python-asyncio,Python 3.x,Async Await,Python 3.6,Python Asyncio,我的用例是运行一些性能测试,所以我想创建一个应用程序,其中我运行1个任务4次,计算该任务的平均时间,然后异步运行2个任务,计算平均时间,然后异步运行4个任务,计算平均时间,然后8个任务,依此类推 但是,我不能这样跑。当我这么做的时候,所有的任务似乎都已经执行过了,我的时间错了 我尝试了一些尝试,使用下面的代码,现在我得到了TypeError:asyncio.Future,一个corroutine或一个waitible是必需的 sys:1:RuntimeWarning:coroutine“go”从

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

但是,我不能这样跑。当我这么做的时候,所有的任务似乎都已经执行过了,我的时间错了

我尝试了一些尝试,使用下面的代码,现在我得到了
TypeError:asyncio.Future,一个corroutine或一个waitible是必需的
sys:1:RuntimeWarning:coroutine“go”从未在
循环中等待过。在
运行任务
函数中运行直到完成(asyncio.wait(asyncio.sure_future(某些任务))

下面是我的代码:

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())    
async def go(日期):
pool=wait aiopg.create_pool(“**db connection**”)
将pool.acquire()作为conn进行异步:
以conn.cursor()作为cur的异步:
等待cur.execute(““某些查询”)
时间。睡眠(1)
ret=[]
当前行的异步:
ret.append(行)
定义日期范围(日期1、日期2):
对于范围内的n(int((date2-date1).days)+1):
产量日期1+时间增量(n)
def run_任务():
开始时间=日期时间(2017年8月9日)
end_dt=日期时间(2017年8月10日)
任务=[]
一些任务=[]
平均运行时间=[]
对于日期范围内的日期(开始日期、结束日期):
#tasks.append(asyncio.sure_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
而我<2:#我<128
#从任务列表中获取任务数
对于范围内的k(上一个,i):
一些任务。追加(任务[k])
prev=len(某些任务)
运行时间=[]
对于范围(0,4)内的j:#重复任务4次
开始=时间。时间()
loop=asyncio.get\u event\u loop()
loop.run_直到_完成(asyncio.wait(asyncio.sure_future(某些_任务)))
#loop.close()
end=time.time()
差异=结束-开始
运行时间附加(差异)
打印(“ith SomeTask:{},{}”。格式(i,someu任务))
打印(“总时间:{}”。格式(差异))
#获取每个任务运行4次的平均值
平均时间运行。追加(总和(时间运行)/浮动(长度(时间运行)))
i*=2
返回平均运行时间
打印(运行任务()
一些提示将不胜感激。我应该把wait放在哪里,因为它在那里是
asyncio.wait

asyncio.ensure_future(some_tasks)
您正在将协同路由列表传递给
asyncio。请确保未来
。正如您在中所看到的,这并不是这个函数的工作方式:您应该传递单个协程来创建。这就是为什么您会得到
TypeError
,您会得到
RuntimeWarning
,因为创建了
go
,所以没有等待协同程序作为上述结果

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

loop.run_until_complete(asyncio.wait(some_tasks))

还有一件事很重要:

time.sleep(1)
您永远不应该在协程内部执行此操作:它会冻结您的事件循环(以及所有与之相关的协程)。请阅读了解asyncio的一般工作原理

如果您想在协同程序中休息一段时间,请使用:

应答码:

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())
async def run(date)://对于采用,请检查上面的go()函数
conn=等待异步PG.connect(“db连接”)
values=wait conn.fetch(““某些查询”)
等待asyncio.sleep(1)
等待控制室关闭
定义日期范围(日期1、日期2):
对于范围内的n(int((date2-date1).days)+1):
产量日期1+时间增量(n)
def run_任务():
开始时间=日期时间(2017年8月9日)
end_dt=日期时间(2017年8月10日)
任务=[]
平均运行时间=[]
i=1
当i<9时,任务数增加
运行时间=[]
开始=时间。时间()
loop=asyncio.get\u event\u loop()
对于日期范围内的日期(开始日期、结束日期):
如果len(任务)
谢谢@Mikhail。我也试了一些东西,发现了错误。还有,我做了一些改变。请看我的答案,并让我知道任何改进。另一个快速的问题是,我应该把loop.close()放在哪里,因为我把它放在哪里就表明任务正在运行?@Atihska在编写asyncio脚本时,应该确保所有任务都已完成,并且在执行结束时等待所有创建的协程。相反的意思通常意味着代码中有错误
loop.close()
可以通过发出警告来帮助您查看它。这就是为什么它通常放在脚本的末尾。如果我没有弄错,请将它放在
print(run_tasks())
之后,您更新的代码现在不应该发出警告。如果它有效,我想没问题。我唯一要更改的是在
运行
中创建/关闭连接时添加
try finally
块。示例可以在@MikhailGerasimov中找到,好的,我应该使用g吗
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())