如何使用asyncio进行并行任务

11

我在想如何使用asyncio来处理类似于nodeJS的任务。我希望能够同时运行多个任务而不需要打开线程。 示例:

import asyncio
 
@asyncio.coroutine
def my_coroutine(task_name, seconds_to_sleep=3):
    print('{0} sleeping for: {1} seconds'.format(task_name, seconds_to_sleep))
    yield from asyncio.sleep(seconds_to_sleep)
    print('{0} is finished'.format(task_name))
 
 
loop = asyncio.get_event_loop()
tasks = [
    my_coroutine('task1', 4),
    my_coroutine('task2', 3),
    my_coroutine('task3', 2)]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()

将输出:

task1 sleeping for: 4 seconds
task2 sleeping for: 3 seconds
task3 sleeping for: 2 seconds
task3 is finished
task2 is finished
task1 is finished

但是当我尝试使用不同的任务时,它就不能像那样工作。
import asyncio
import timeit
 
@asyncio.coroutine
def my_coroutine(task_name):
    print('order placed for ' + task_name)
    print(timeit.timeit('1 + 3 ', number=50000000))
    print(task_name + ' done')
 
 
loop = asyncio.get_event_loop()
tasks = [
    my_coroutine('task1'),
    my_coroutine('task2'),
    my_coroutine('task3')]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()

输出

order placed for task2
0.6677237730912453
task2 done
order placed for task1
0.6627442526498016
task1 done
order placed for task3
0.665618849882418
task3 done

asyncio 不并行运行任务。它运行一个任务直到等待,然后继续下一个任务。你第一个示例中的 sleep 是使任务相互让出控制权。你的第二个示例没有等待任何内容,因此每个任务都会运行直到完成,然后事件循环才能将控制权交给另一个任务。 - dirn
我看了。那么我该如何将我的第二段代码变成异步任务呢?我尝试添加yield from,但它仍然不像第一个示例那样工作。 - Zepol
你是如何添加 yield from 的?你是添加了 yield from asyncio.sleep(n) 还是做了其他的事情? - dirn
我做了其他事情。我不确定应该如何完成,但基本上,我想做第二个示例中的内容。你能给我展示一下吗? - Zepol
请参考以下相关问题:https://dev59.com/wF4b5IYBdhLWcg3wWwTQ - songololo
2个回答

12

asyncio不会并行运行任务。它会运行一个任务,直到它等待,然后转移到下一个任务。您第一个示例中的sleep是使任务相互让出控制的原因。您的第二个示例没有等待任何内容,因此每个任务在事件循环可以将控制权交给另一个任务之前都会运行到完成。

如果您在协程中添加一个可等待对象(例如asyncio.sleep),则每个对象都将让出控制权并为其他对象提供运行机会。

@asyncio.coroutine
def my_coroutine(task_name):
    print('order placed for ' + task_name)
    yield from asyncio.sleep(0)  # Another coroutine will resume here.
    print(timeit.timeit('1 + 3 ', number=50000000))
    yield from asyncio.sleep(0)  # Another coroutine will resume here.
    print(task_name + ' done')

7

asyncio文档指出asyncio任务是并发运行而非并行运行。

asyncio是使用async/await语法编写并发代码的库。

@asyncio.coroutinePython 3.7.14开始弃用,并在Python 3.11.0中被移除,因此您应该按照下面的示例使用async

# @asyncio.coroutine
async def test():
    print("Test")

例如,以下代码:

import asyncio

async def test1():
    for _ in range(0, 3):
        print("Test1")
        
async def test2():
    for _ in range(0, 3):
        print("Test2")
        
async def test3():
    for _ in range(0, 3):
        print("Test3")

async def call_tests():
    await asyncio.gather(test1(), test2(), test3())

asyncio.run(call_tests())

test1()test2()test3() 将按照下面的顺序依次运行:

Test1 # 0 second
Test1 # 0 second
Test1 # 0 second
Test2 # 0 second
Test2 # 0 second
Test2 # 0 second
Test3 # 0 second
Test3 # 0 second
Test3 # 0 second

如果在以下代码中使用await asyncio.sleep(1)

import asyncio

async def test1():
    for _ in range(0, 3):
        print("Test1")
        await asyncio.sleep(1) # Here
        
async def test2():
    for _ in range(0, 3):
        print("Test2")
        await asyncio.sleep(1) # Here

async def test3():
    for _ in range(0, 3):
        print("Test3")
        await asyncio.sleep(1) # Here

async def call_tests():
    await asyncio.gather(test1(), test2(), test3())

asyncio.run(call_tests())

他们交替运行,每次睡眠1秒,如下所示:
Test1 # 1 second
Test2 # 1 second
Test3 # 1 second
Test1 # 2 seconds
Test2 # 2 seconds
Test3 # 2 seconds
Test1 # 3 seconds
Test2 # 3 seconds
Test3 # 3 seconds

如果在以下代码中使用await asyncio.sleep(0)

import asyncio

async def test1():
    for _ in range(0, 3):
        print("Test1")
        await asyncio.sleep(0) # Here
        
async def test2():
    for _ in range(0, 3):
        print("Test2")
        await asyncio.sleep(0) # Here

async def test3():
    for _ in range(0, 3):
        print("Test3")
        await asyncio.sleep(0) # Here

async def call_tests():
    await asyncio.gather(test1(), test2(), test3())

asyncio.run(call_tests())

他们会交替运行,不会休息,如下所示:
Test1 # 0 second
Test2 # 0 second
Test3 # 0 second
Test1 # 0 second
Test2 # 0 second
Test3 # 0 second
Test1 # 0 second
Test2 # 0 second
Test3 # 0 second

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接