Python asyncio非阻塞循环

时间:2019-07-24 03:49:03

标签: python asyncio

(我使用的是Python 3.7)

import asyncio


result = 0


async def sub1():
    global result
    print('[*] sub1() start')
    for i in range(1, 10000000):
        result += i
    print('[*] sub1() end')

async def sub2():
    global result
    print('[*] sub2() start')
    for i in range(10000000, 20000000):
        result += i
    print('[*] sub2() end')

async def main():
    await asyncio.gather(
        asyncio.create_task(sub1()),
        asyncio.create_task(sub2()),
    )


asyncio.run(main())

当我执行上面的代码时,结果是

[*] sub1() start
[*] sub1() end
[*] sub2() start
[*] sub2() end
[Finished in 1.7s]

您知道sub2()是在sub1()完成之后开始的。

似乎无法并行工作。

我想将控制权交给sub2(),直到sub1()完成。

也许我必须将await插入某处,但我不知道这是哪里。

问题

如何使用for循环并行执行两个函数?

谢谢。

1 个答案:

答案 0 :(得分:1)

正如@KlausD在他的评论中指出的那样,仅添加async标记并不能有效地使您的代码真正异步。 asynciofor-loops中需要某种断点,以有效地知道何时在功能之间进行切换。这是一个利用同步功能并在循环的executordocumentation here)中运行它们的可行解决方案:

import asyncio

result = 0

def sub1():
    global result
    print('[*] sub1() start')
    for i in range(1, 10000000):
        result += i
    print('[*] sub1() end')

def sub2():
    global result
    print('[*] sub2() start')
    for i in range(10000000, 20000000):
        result += i
    print('[*] sub2() end')

async def main(loop):
    res = await asyncio.gather(
        loop.run_in_executor(None, sub1),
        loop.run_in_executor(None, sub2)
    )


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

值得注意的是,编写异步代码必须记住要进行确保代码实际上异步运行的实践。实际上,Python中的本机for-loop是一段同步代码,因此,在调用函数时,for循环将运行到完成,然后在线程中为下一个操作留出空间。

另一件事是,由于代码是简单的添加,因此实际上并没有通过异步运行代码节省任何时间。糟糕,您可能由于asyncio操作必须在功能之间切换而浪费时间。异步功能非常适合需要在操作之间进行某种等待的大型处理(例如,进行各种服务器调用,其中一个必须等​​待服务器响应;读取多个文件,其中一个必须取决于硬盘驱动器的读取速度,在这种情况下,异步变得很有用,因为可以切换线程内的操作并确保在运行继续处理线程之前调用 all (从服务器中拉出;从硬盘驱动器中获取文件)的所有调用。请求或文件。