【问题标题】:How to run an Asyncio task without awaiting?如何在不等待的情况下运行 Asyncio 任务?
【发布时间】:2021-10-16 14:31:51
【问题描述】:

我需要定期调用任务,但 (a) 等待时间几乎超过了周期。

在下面的代码中,如何运行do_something() 任务而不需要await 获得结果?

 import asyncio
 import time
 from random import randint

 period = 1  # Second


 def get_epoch_ms():
     return int(time.time() * 1000.0)


 async def do_something(name):
     print("Start  :", name, get_epoch_ms())
     try:
         # Do something which may takes more than 1 secs.
         slp = randint(1, 5)
         print("Sleep  :", name, get_epoch_ms(), slp)
         await asyncio.sleep(slp)
     except Exception as e:
         print("Error  :", e)

     print("Finish :", name, get_epoch_ms())


 async def main():
     i = 0
     while True:
         i += 1
         # Todo : this line should be change
         await do_something('T' + str(i))
         await asyncio.sleep(period)


 asyncio.get_event_loop().run_until_complete(main())

【问题讨论】:

  • 等待结果的时间不可能比产生结果的时间更短。你能更详细地描述一下这个问题吗?
  • 是的,当然。我正在使用 API 调用从多个网站获取加密货币数据。我的目标是以恒定周期(最后周期的平均值)调用获取数据 API。让我们假设每分钟 60 个请求。有些网站懒得回答。例如,假设所有响应将在 10 秒后交付。真的我不在乎什么时候会收到响应(甚至在 60 秒后它可能会出现超时错误)。这等待 API 响应很烦人。我只想发送相同周期的请求。

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


【解决方案1】:

您的问题是使用不满足您的并发目的的run_until_complete(main())。所以,假设你的协程任务(do_something())绑定到5,你的代码如下:

import time
from random import randint

period = 1  # Second

def get_epoch_ms():
    return int(time.time() * 1000.0)

async def do_something(name):
    print("Start  :", name, get_epoch_ms())
    try:
        # Do something which may takes more than 1 secs.
        slp = randint(1, 5)
        print("Sleep  :", name, get_epoch_ms(), slp)
        await asyncio.sleep(slp)
    except Exception as e:
        print("Error  :", e)

    print("Finish :", name, get_epoch_ms())

loop = asyncio.get_event_loop()
futures = [loop.create_task(do_something('T' + str(i)))
           for i in range(5)]

loop.run_forever()

for f in futures:
    f.cancel()

这是其输出中的并发工作流:

Start  : T0 1558937750705
Sleep  : T0 1558937750705 5
Start  : T1 1558937750705
Sleep  : T1 1558937750705 1
Start  : T2 1558937750705
Sleep  : T2 1558937750705 4
Start  : T3 1558937750705
Sleep  : T3 1558937750705 5
Start  : T4 1558937750705
Sleep  : T4 1558937750705 5
Finish : T1 1558937751707
Finish : T2 1558937754709
Finish : T0 1558937755707
Finish : T3 1558937755708
Finish : T4 1558937755708

但是,如果您的协程任务不受限制,您可以这样做:

...
async def main(loop):
    i = 0
    while True:
        i += 1
        loop.create_task(do_something('T' + str(i)))
        await asyncio.sleep(period)

loop = asyncio.get_event_loop()
loop.run_until_complete(main(loop))

【讨论】:

    【解决方案2】:

    调用asyncio.create_task 来生成在后台运行的任务对象,而不是await 协同程序。在您的下一次迭代中,您可以检查任务是否已完成并相应地等待/取消它。 (否则 asyncio 会抱怨未等待的任务被垃圾收集。)

    【讨论】:

      猜你喜欢
      • 2012-01-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-06
      • 2017-06-05
      相关资源
      最近更新 更多