繁体   English   中英

如何创建一个包含for循环非阻塞的函数?

[英]How to make a function that includes a for loop non-blocking?

我试图使下面的代码异步:

import asyncio
import random

async def count():
    l = []
    for i in range(10000000):
        l.append(i)
    return random.choice(l)

async def long_task1():
    print('Starting task 1...')
    task_output = await count()
    print('Task 1 output is {}'.format(task_output ))


async def long_task2():
    print('Starting task 2...')
    task_output = await count()
    print('Task 2 output is {}'.format(task_output ))

async def main():
    await asyncio.gather(long_task1(), long_task2())

if __name__ == '__main__':
    asyncio.get_event_loop().run_until_complete(main())

目前它将同步工作。

是因为count函数缺少await语句吗?

我已经尝试重新处理函数以包括await

async def count():
    l = []
    for i in range(10000000):
        l.append(i)
    choice = await random.choice(l)
    return choice

它将以异步方式启动( Starting task 1...Starting task 2...将一个接一个地打印),但后来我收到错误:

TypeError:object int不能在'await'表达式中使用

我知道错误的发生是因为random.choice(l)的结果不是一个等待的(协程),但我不知道如何解决这个问题,而不是在圈内运行。 我是否需要以某种方式将for循环重构为一个独立的couroutine?

是因为count函数缺少await语句吗?

简而言之,是的,您已正确识别问题。 要获得并行执行任务,您不仅需要指定async def ,还需要等待暂停执行的内容,从而将控制权返回给事件循环。 在asyncio中,这通常是一种阻止同步程序的调用,例如睡眠或从尚未准备好读取的套接字读取。

要强制临时暂停 ,可以在循环内添加await asyncio.sleep(0)count random.choice之类的普通函数前添加await random.choice ,因为await需要一个实现等待接口的对象,并且在你的代码中random.choice只返回一个整数。

您的代码调用同时运行long_task1long_task2gather 然后在每个函数中调用await on count 但这将await该子程序完成。 因此整个子程序仍将在下一个子程序开始之前完成。 您需要一个函数来暂停整个任务。 我创造了两种方法来规避这一点。 两者都涉及创建新任务。

创建一个新的子程序:

async def count():
   l = []
   await asyncio.wait_for(loopProcess(l), timeout=1000000.0)
   return random.choice(l)

async def loopProcess(l):
   for i in range(10000000):
      l.append(i)

您还可以使count功能与原始代码保持一致,并像这样更改long_task(1/2)以使count()成为一项新任务:

async def long_task1():
   print('Starting task 1...')
   task_output = await asyncio.shield(count())
   print('Task 1 output is {}'.format(task_output ))


async def long_task2():
   print('Starting task 2...')
   task_output = await asyncio.shield(count())
   print('Task 2 output is {}'.format(task_output ))

如果你有python 3.7,你也可以使用create_task

资料来源: https//docs.python.org/3/library/asyncio-task.html

为了使asyncio正常工作,您不应该在事件循环中有任何cpu密集型任务(紧密的大循环)。 因为没有办法摆脱for循环。 如果你在循环中使用一个显式的asyncio.sleep ,你就会不必要地进出协程并减慢整个过程。 如果你的目标只是看看asyncio如何工作,那很好。

但在现实世界中,如果你有一个cpu密集型任务,你有两个选择

  1. 使用多处理并将任务委派给其他进程。
  2. 使用释放GIL并使用线程的本机代码绑定。

顾名思义,该库用于异步io。 async"io"

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM