python:协程及任务创建
Python 中的协程(Coroutine)是一种可以暂停和恢复执行的函数,用于实现异步编程。它在 I/O 密集型任务中非常有用,比如网络请求、文件读写等,可以在等待时切换到其他任务,从而提高程序效率。
一、基本概念
- 协程 vs 线程:协程是用户态的轻量级“线程”,由程序员控制调度(协作式多任务),而线程由操作系统调度(抢占式多任务)。
- async / await:Python 3.5+ 引入了
async def和await语法,成为定义和使用协程的标准方式。
二、定义协程
import asyncio
async def calculate(n1:int , n2:int):
return n1 + n2
result = calculate(1,2)
print(result)
运行结果如下:

说明你调用了 async def calculate(...),但没有用 await 或 asyncio.run() 来真正执行它。Python 只是创建了一个协程对象,然后就结束了程序,导致协程“被遗忘”,于是发出警告。
✅ 正确解决方法
✅ 方法 1:直接用 asyncio.run() 执行协程(适合简单脚本)
import asyncio
async def calculate(n1:int , n2:int):
result = n1 + n2
print(result)
asyncio.run(calculate(1,2))
将事件函数calculate扔进协程的run函数程序进行异步执行。
运行结果如下:

💡 注意:asyncio.run() 只能在主线程顶层调用一次,不能嵌套使用。
✅ 方法 2:在 async 函数中 await(推荐用于复杂逻辑)
import asyncio
async def calculate(n1:int , n2:int):
result = n1 + n2
print(result)
async def main():
#在本协程中调用另一个协程,要使用await
print("main -step 1")
await calculate(1,2)
print("main -step 2")
asyncio.run(main())
在 Python 中,await 是用于异步编程的关键字,必须在异步函数(async def 定义的函数) 中使用,其作用是暂停当前异步函数的执行,等待一个可等待对象(Awaitable) 完成,并获取其结果,期间事件循环可以去执行其他任务,实现异步并发。
可等待对象(Awaitable)
await 后面必须跟可等待对象,主要包括以下三类:
- 协程对象(Coroutine):由
async def定义的函数调用后返回的对象。 - 任务对象(Task):通过
asyncio.create_task()或asyncio.ensure_future()创建的对象,用于并发执行协程。 - 未来对象(Future):表示异步操作的最终结果,是底层的异步原语,通常很少直接使用。
运行结果如下:

三、创建任务
import asyncio
import time
async def call_api(name:str,delay:float):
print(f"{name} -step 1")
await asyncio.sleep(delay)
print(f"{name} -step 2")
async def main():
#计算消耗的时候
time_1 = time.perf_counter()
print("start a coroutine")
await call_api("A",3)
print("finished A coroutine")
print("start b coroutine")
await call_api("B", 3)
print("finished B coroutine")
time_2 = time.perf_counter()
print(f"Spent{time_2 - time_1}")
asyncio.run(main())
运行结果如下:

相当于整个程序执行完了A,A结束了之后再去执行B,在A“睡眠”的3秒钟时间里面,没有去执行B任务,也就是说A和B两个协程没有并行执行。
那要怎么并行执行呢,这里就要用到asyncio.create_task()
asyncio.create_task() 是 Python 异步编程中用于并发调度协程的重要函数。它将一个协程(coroutine)封装为一个 Task 对象,并立即安排到事件循环中执行,而无需等待你显式 await 它(但通常你仍会 await 以获取结果或处理异常)。
使用asyncio.create_task()的代码如下:
import asyncio
import time
async def call_api(name:str,delay:float):
print(f"{name} -step 1")
await asyncio.sleep(delay)
print(f"{name} -step 2")
async def main():
#计算消耗的时候
time_1 = time.perf_counter()
print("start a coroutine")
asyncio.create_task(call_api("A",3))
print("finished A coroutine")
print("start b coroutine")
asyncio.create_task(call_api("B", 3))
print("finished B coroutine")
time_2 = time.perf_counter()
print(f"Spent{time_2 - time_1}")
asyncio.run(main())
运行结果:

这段代码的核心问题是:创建了异步任务但没有等待任务完成,导致程序在任务执行前就结束了。
具体表现:
asyncio.create_task()只是创建任务并加入事件循环,但不会阻塞当前协程main()函数在创建完任务后立即结束,事件循环随之关闭,任务根本来不及执行- 最终输出的耗时几乎为 0,且看不到
step 1和step 2的打印(或只能看到部分)
核心原因分析:
根本原因是:main协程执行完毕后,事件循环直接退出,未等待创建的异步任务完成。
异步编程中,asyncio.run(main())的作用是:
- 创建一个新的事件循环;
- 运行
main协程直到其完成; - 关闭事件循环(无论是否有其他任务未完成)。
而asyncio.create_task(coro)只是将协程包装为任务(Task)并加入事件循环的待执行队列,但不会阻塞当前协程(即main会继续往下执行,不会等任务运行)。
当main协程执行到最后一行(print(f"Spent..."))后,main就完成了,此时事件循环被asyncio.run关闭,所有未完成的任务(A 和 B)会被直接终止,因此step2永远不会执行,甚至step1也可能因事件循环关闭过快而无法执行。
四、使用await等待
修正后的代码
我们需要通过 await 等待所有任务完成,代码如下:
import asyncio
import time
async def call_api(name:str,delay:float):
print(f"{name} -step 1")
await asyncio.sleep(delay)
print(f"{name} -step 2")
async def main():
#计算消耗的时候
time_1 = time.perf_counter()
print("start a coroutine")
task_1 = asyncio.create_task(call_api("A",3))
print("finished A coroutine")
print("start b coroutine")
task_2 = asyncio.create_task(call_api("B", 3))
print("finished B coroutine")
# 等待所有任务完成(关键步骤)
await task_1
print("task_1 completed")
await task_2
print("task_2 completed")
time_2 = time.perf_counter()
print(f"Spent{time_2 - time_1}")
asyncio.run(main())
运行结果如下:

我们将任务2中的睡眠时间更改为2秒钟,看下结果如何:
task_2 = asyncio.create_task(call_api("B", 2))
运行结果如下:

将任务1的睡眠时间调整为10秒钟,再看一下效果:


浙公网安备 33010602011771号