hello
world
2、创建一个task 协程对象不能直接运行,在注册到事件循环的时候,其实是run_until_complete方法将协程包装成一个task对象,所谓的task对象就是Future类的子类,它保存了协程运行后的状态,用于未来获取协程的结果。
创建task后,task在加入事件循环之前是pending状态,因为下例中没有耗时操作,task很快会完成,后面打印finished状态。
import asyncio
async def work(x): # 通过async关键字定义一个协程
for _ in range(3):
print('Work {} is running ..'.format(x))
coroutine_1 = work(1) # 协程是一个对象,不能直接运行
loop = asyncio.get_event_loop()
task = loop.create_task(coroutine_1)
# task = asyncio.ensure_future(coroutine_1) # 这样也能创建一个task
print(task)
loop.run_until_complete(task) # run_until_complete接受的参数是一个future对象,当传人一个协程时,其内部自动封装成task
print(task)
<Task pending coro=<work() running at <ipython-input-9-bebcb42450f1>:3>>
Work 1 is running ..
Work 1 is running ..
Work 1 is running ..
<Task finished coro=<work() done, defined at <ipython-input-9-bebcb42450f1>:
isinstance(task, asyncio.Future) # task 是 Future的子类
补:isinstance() 函数来判断一个对象是否是一个已知的类型,类似 type()。
isinstance() 与 type() 区别:
type() 不会认为子类是一种父类类型,不考虑继承关系。
isinstance() 会认为子类是一种父类类型,考虑继承关系。
3、绑定回调 在task执行完毕的时候可以获取执行的结果,回调的最后一个参数是future对象,通过这个对象可以获取协程的返回值,如果回调函数需要多个参数,可以通过偏函数导入。
从下例可以看出,coroutine执行结束时候会调用回调函数,并通过future获取协程返回(return)的结果。我们创建的task和回调里面的future对象,实际上是同一个对象。
import asyncio
async def work(x):
for _ in range(3):
print('Work {} is running ..'.format(x))
return "Work {} is finished".format(x)
def call_back(future):
print("Callback: {}".format(future.result()))
coroutine = work(1)
loop = asyncio.get_event_loop()
task = asyncio.ensure_future(coroutine)
task.add_done_callback(call_back)
loop.run_until_complete(task) # 返回任务的结果
Work 1 is running ..
Work 1 is running ..
Work 1 is running ..
Callback: Work 1 is finished
'Work 1 is finished'
当回调函数需要传递多个参数时,可以使用functools里的partial方法(偏函数导入这些参数)
functools.partial(func, * args, * * keywords),函数装饰器,返回一个新的partial对象。调用partial对象和调用被修饰的函数func相同,只不过调用partial对象时传入的参数个数通常要少于调用func时传入的参数个数。当一个函数func可以接收很多参数,而某一次使用只需要更改其中的一部分参数,其他的参数都保持不变时,partial对象就可以将这些不变的对象冻结起来,这样调用partial对象时传入未冻结的参数,partial对象调用func时连同已经被冻结的参数一同传给func函数,从而可以简化调用过程。
如果调用partial对象时提供了更多的参数,那么他们会被添加到args的后面,如果提供了更多的关键字参数,那么它们将扩展或者覆盖已经冻结的关键字参数。
具体的偏函数使用方法见下例:
from functools import partial
def func(a, b):
return a + b
# 正常使用
result = func(1, 2)
# 使用偏函数导入一个参数,返回一个新函数
new_func = partial(func, 1) # 相当于把原函数中的第一个参数a固定一个值为1,新函数只需要传入一个参数b即可
result2 = new_func(2)
print(result, result2)
# 3 3
import asyncio
import functools
async def work(x):
for _ in range(3):
print('Work {} is running ..'.format(x))
return "Work {} is finished".format(x)
def call_back_2(num, future):
print("Callback_2: {}, the num is {}".format(future.result(), num))
coroutine = work(1)
loop = asyncio.get_event_loop()
task = asyncio.ensure_future(coroutine)
task.add_done_callback(functools.partial(call_back_2, 100))
loop.run_until_complete(task)
Work 1 is running ..
Work 1 is running ..
Work 1 is running ..
Callback_2: Work 1 is finished, the num is 100
'Work 1 is finished'
在不绑定回调函数的时候,当task处于finished的状态时,可以直接读取task的result的值
import asyncore
async def work(x):
for _ in range(3):
print("Work {} is running ..".format(x))
return "Work {} is finished".format(x)
coroutine = work(1)
loop = asyncio.get_event_loop()
task = asyncio.ensure_future(coroutine)
loop.run_until_complete(task)
print("The task's result is '{}'".format(task.result()))
Work 1 is running ..
Work 1 is running ..
Work 1 is running ..
The task's result is 'Work 1 is finished'
4、阻塞和await 使用async可以定义协程对象,使用await可以正对耗时操作进行挂起,就像生成器里的yield一样,函数让出控制权。 协程遇到await,事件循环就会挂起这个协程,执行别协程,直到其他协程也挂起或执行完毕,在进行下一个协程的执行。
如果一个对象可以在 await 语句中使用,那么它就是 可等待 对象。
耗时操作一般指IO操作: 网络请求,文件读取等,使用asyncio.sleep模拟耗时操作。协程的目的也是让这些IO操作异步化。
4-1、并发运行任务:
asyncio.gather(* aws,loop = None,return_exceptions = False ) 同时在aws 序列中运行等待对象。
- 如果在aws中等待的是协程,它将自动调度为任务。
- 如果所有等待都成功完成,则结果是返回值的汇总列表。结果值的顺序对应于aws中的等待顺序。
- 如果return_exceptions是False(默认),则第一个引发的异常会立即传播到等待的任务gather()。aws序列 中的其他等待项将不会被取消并继续运行。
- 如果return_exceptions是True,异常的处理方式一样成功的结果,并在结果列表汇总。
- 如果gather()被取消,所有提交的awaitables(尚未完成)也被取消。
- 如果aws序列中的任何任务或未来被取消,则将其视为已引发CancelledError- 在这种情况下不会取消gather() 呼叫。这是为了防止取消一个提交的任务/未来以导致其他任务/期货被取消。
# 并发运行任务的案例
import asyncio
async def factorial(name, number):
f = 1
for i in range(2, number + 1):
print(f"Task {name}: Compute factorial({i})...") # python3.7新语法,了解一波
await asyncio.sleep(1) # await后面是 可等待对象
f *= i
print(f"Task {name}: factorial({number}) = {f}")
return f"Task {name}: Finished!"
async def main():
# Schedule three calls *concurrently*:
results = await asyncio.gather( # results包含所有任务的返回结果,是一个列表,按执行顺序返回结果
factorial("A", 2), # 协程,会自动调度为任务
factorial("B", 3),
factorial("C", 4),
print(results)
asyncio.run(main()) # 协程的嵌套,后面有详解
Task A: Compute factorial(2)...
Task B: Compute factorial(2)...
Task C: Compute factorial(2)...
Task A: factorial(2) = 2
Task B: Compute factorial(3)...
Task C: Compute factorial(3)...
Task B: factorial(3) = 6
Task C: Compute factorial(4)...
Task C: factorial(4) = 24
['Task A: Finished!', 'Task B: Finished!', 'Task C: Finished!']
4-2、屏蔽取消操作:
asyncio.shield(aw, * , loop=None) 保护一个 可等待对象 防止其被 取消。如果 aw 是一个协程,它将自动作为任务加入日程。
- res = await shield(something()) 相当于: res = await something()
不同之处 在于如果包含它的协程被取消,在 something() 中运行的任务不会被取消。从 something() 的角度看来,取消操作并没有发生。然而其调用者已被取消,因此 “await” 表达式仍然会引发 CancelledError。
res = await shield(something())
except CancelledError:
res = None
4-3、超时:
asyncio.wait_for(aw, timeout, * , loop=None) 等待 aw 可等待对象 完成,指定 timeout 秒数后超时。
- 如果 aw 是一个协程,它将自动作为任务加入日程。
- timeout 可以为 None,也可以为 float 或 int 型数值表示的等待秒数。如果 timeout 为 None,则等待直到完成。
- 如果发生超时,任务将取消并引发 asyncio.TimeoutError.
- 要避免任务 取消,可以加上 shield()。函数将等待直到目标对象确实被取消,所以总等待时间可能超过 timeout 指定的秒数。如果等待被取消,则 aw 指定的对象也会被取消。
- loop 参数已弃用,计划在 Python 3.10 中移除。
# 超时的案例
import asyncio
async def eternity():
# Sleep for one hour
# await asyncio.sleep(0.5)
await asyncio.sleep(3600)
print('yay!')
async def main():
# Wait for at most 1 second
await asyncio.wait_for(eternity(), timeout=1.0) # 等待 可等待对象 完成,超过timeout秒后,抛出asyncio.TimeoutError异常
except asyncio.TimeoutError:
print('timeout!')
asyncio.run(main())
# timeout!
4-4、简单等待:
asyncio.wait(aws,* , loop = None,timeout = None,return_when = ALL_COMPLETED ) 同时运行aws中的等待对象 并阻塞 ,直到return_when指定的条件。
- 返回两组tasks/futures:(done,pending)
- 用法:done, pending = await asyncio.wait(aws)
- return_when 指定此函数应在何时返回。它必须为以下常数之一:
- FIRST_COMPLETED 函数将在任意可等待对象结束或取消时返回。
- FIRST_EXCEPTION 函数将在任意可等待对象因引发异常而结束时返回。当没有引发任何异常时它就相当于 ALL_COMPLETED。
- ALL_COMPLETED 函数将在所有可等待对象结束或取消时返回。
与 wait_for() 不同,wait() 在超时发生时不会取消可等待对象。
# 简单等待的案例
import asyncio
async def foo():
return 42
task = asyncio.create_task(foo())
# 注意:1、这里传递的要是一个任务组,而不能是单个task,如果只有一个任务,可以这样传递:[task](task,){task}
# 2、直接传递协程对象的方式已弃用 即:done, pending = await asyncio.wait([foo()])
done, pending = await asyncio.wait((task, ))
if task in done:
print(f"The task's result is {task.result()}")
# The task's result is 42
asyncio.as_completed(aws, * , loop=None, timeout=None) 并发地运行 aws 集合中的 可等待对象。返回一个 Future 对象的迭代器。返回的每个 Future 对象代表来自剩余可等待对象集合的最早结果。
- 如果在所有 Future 对象完成前发生超时则将引发 asyncio.TimeoutError。
- 示例:
for f in as_completed(aws):
earliest_result = await f
# 使用事件循环和asyncio.wait、asyncio.gather实现并发运行任务
import asyncio, time
async def work_1(x):
print(f"Starting {x}")
time.sleep(1)
print(f"Starting {x}")
for _ in range(3):
print(f"Work {x} is running ..")
await asyncio.sleep(2) # 耗时操作,此时挂起该协程,执行其他协程
return f"Work {x} is finished"
async def work_2(x):
print(f"Starting {x}")
for _ in range(3):
await asyncio.sleep(1) # 耗时操作,此时挂起该协程,执行其他协程
print(f"Work {x} is running ..")
return f"Work {x} is finished"
coroutine_1 = work_1(1)
coroutine_2 = work_2(2)
loop = asyncio.get_event_loop() # 创建一个事件循环
# 方式一,asyncio.wait(tasks)接受一个task列表 执行的顺序与列表里的任务顺序有关
tasks = [
asyncio.ensure_future(coroutine_1),
asyncio.ensure_future(coroutine_2),
# 注册到事件循环中,并执行
dones, pendings = loop.run_until_complete(asyncio.wait(tasks)) # loop.run_until_complete(asyncio.wait(tasks))的作用相当于:await asyncio.wait(tasks)
for task in dones:
print(task.result())
# 方式二,使用asyncio.gather(*tasks),接受一堆tasks,tasks也可以是一个列表,使用*解包
# task_1 = asyncio.ensure_future(coroutine_1)
# task_2 = asyncio.ensure_future(coroutine_2)
# task_result_list = loop.run_until_complete(asyncio.gather(task_1, task_2)) # 返回一个列表,里面包含所有task的result()的结果
# print(task_result_list)
Starting 1
Starting 1
Work 1 is running ..
Starting 2
Work 2 is running ..
Work 1 is running ..
Work 2 is running ..
Work 2 is running ..
Work 1 is running ..
Work 1 is finished
Work 2 is finished
上面的执行结果是: 先打印Starting 1,然后等待1秒再次打印Starting 1,Work 1 is running …,Starting 2(这三个是一起出现的,应该是执行太快的原因),由于work2的耗时操作比较短,等待完成后打印Work 2 is running …,接着for循环,再来一轮,work2中再次碰到await,挂起任务,但是work1中的耗时操作还没结束,大家都在等待耗时操作结束,work2正好是2次,2秒,与work1耗时操作同时完成,所以打印Work 1 is running …Work 2 is running …同时出现,最后,第三轮循环,work2等待1秒后打印Work 2 is running …,等待一秒后,work1完成耗时操作,打印Work 1 is running …,异步任务完成。
5、协程嵌套 使用async可以定义协程,协程用于耗时的IO操作。我们也可以封装更多的IO操作过程,在一个协程中await另外一个协程,实现协程的嵌套。
import asyncio, time
async def work(x):
for _ in range(3):
print("Work {} is running ..".format(x))
await asyncio.sleep(1) # 当执行某个协程时,在任务阻塞的时候用await挂起
return "Work {} is finished!".format(x)
async def main_work():
coroutine_1 = work(1)
coroutine_2 = work(2)
coroutine_3 = work(3)
tasks = [
asyncio.ensure_future(coroutine_1),
asyncio.ensure_future(coroutine_2),
asyncio.ensure_future(coroutine_3),
dones, pendings = await asyncio.wait(tasks)
for task in dones:
print("The task's result is : {}".format(task.result()))
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main_work())
Work 1 is running ..
Work 2 is running ..
Work 3 is running ..
Work 1 is running ..
Work 2 is running ..
Work 3 is running ..
Work 1 is running ..
Work 2 is running ..
Work 3 is running ..
The task's result is : Work 2 is finished!
The task's result is : Work 3 is finished!
The task's result is : Work 1 is finished!
# 使用as_completed方法
import asyncio
async def work(x):
for _ in range(3):
print("Work {} is running ..".format(x))
await asyncio.sleep(1) # 当执行某个协程时,在任务阻塞的时候用await挂起
return "Work {} is finished!".format(x)
async def main_work():
coroutine_1 = work(1)
coroutine_2 = work(2)
coroutine_3 = work(3)
tasks = [
asyncio.ensure_future(coroutine_2),
asyncio.ensure_future(coroutine_1),
asyncio.ensure_future(coroutine_3),
for task in asyncio.as_completed(tasks): # 返回一个可迭代对象,每次返回最先完成的任务的结果
result = await task
print(f"The task's result is : {result}")
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main_work())
Work 2 is running ..
Work 1 is running ..
Work 3 is running ..
Work 2 is running ..
Work 1 is running ..
Work 3 is running ..
Work 2 is running ..
Work 1 is running ..
Work 3 is running ..
The task's result is : Work 2 is finished!
The task's result is : Work 1 is finished!
The task's result is : Work 3 is finished!
以上事例,对asyncio的异步协程有了基本的了解,这里,结合python3.7的说明文档,对部分知识再做说明。
运行协程,asyncio提供了三种主要的机制:
1、asyncio.run() 函数用来运行最高层级的入口点,下例的main()函数。此函数总是会创建一个新的事件循环并在结束时关闭之。它应当被用作 asyncio 程序的主入口点,理想情况下应当只被调用一次。
2、await 等待一个协程,也可以启动一个协程。
import asyncio
import time
async def work(delay, msg):
print(f"Task receives the message :'{msg}' ")
await asyncio.sleep(delay)
print(msg)
async def main():
print(f"Started at {time.strftime('%X')}")
await work(1, "hello") # 启动一个协程,但是这是同步执行的
await work(2, "world")
print(f"Finished at time {time.strftime('%X')}")
asyncio.run(main())
# 运行结果:
# 先打印print(f"Task receives the message :'{msg}' ")然后等待1秒后打印“hello”,
# 然后再次打印print(f"Task receives the message :'{msg}' ")等待2秒后打印“world”
Started at 20:03:44
Task receives the message :'hello'
hello
Task receives the message :'world'
world
Finished at time 20:03:47
import asyncio
async def work(x): # 通过async关键字定义一个协程
for _ in range(3):
print('Work {} is running ..'.format(x))
await asyncio.sleep(1)
coroutine_1 = work(1) # 协程是一个对象,不能直接运行
coroutine_2 = work(2)
await coroutine_1 # 启动一个协程,等待它运行完后,继续往下执行(原因是没有将协程对象加到事件循环里,所以按照程序运行方式,顺序执行)
await coroutine_2
print("The main thread")
Work 1 is running ..
Work 1 is running ..
Work 1 is running ..
Work 2 is running ..
Work 2 is running ..
Work 2 is running ..
The main thread
3、asyncio.create_task() 函数用来并发运行作为 asyncio 任务 的多个协程。下例并发运行两个work协程
import asyncio
import time
async def work(delay, msg):
print(f"Task receives the message :'{msg}' ")
print("----1----")
await asyncio.sleep(delay)
print("----2----")
print(msg)
async def main():
task1 = asyncio.create_task(work(1, "hello"))
task2 = asyncio.create_task(work(3, "world"))
print(f"Started at {time.strftime('%X')}")
await task1 # 此时并发运行task1和task2
print("----3----")
await task2
print("----4----")
print(f"Finished at time {time.strftime('%X')}")
asyncio.run(main())
# 运行结果说明,首先asyncio.run(main())创建一个事件循环,并以main为主要程序入口,
# 在main中,
# 1、创建俩个任务task1和task2,并加入到事件循环中,
# 2、打印Started at 11:16:08
# 3、执行await task1,此时是并发运行了task1和task2了,
Started at 20:42:50
Task receives the message :'hello'
----1----
Task receives the message :'world'
----1----
----2----
hello
----3----
----2----
world
----4----
Finished at time 20:42:53
import asyncio
async def work(x): # 通过async关键字定义一个协程
for _ in range(3):
print('Work {} is running ..'.format(x))
await asyncio.sleep(x)
coroutine_1 = work(1) # 协程是一个对象,不能直接运行
coroutine_2 = work(2)
task1 = asyncio.create_task(coroutine_1) # 将时间加入了运行队列里,可以并发运行
task2 = asyncio.create_task(coroutine_2)
await task1 # 并发运行
await task2
print("The main thread")
Work 1 is running ..
Work 2 is running ..
Work 1 is running ..
Work 2 is running ..
Work 1 is running ..
Work 2 is running ..
The main thread
可等待对象: 如果一个对象可以在 await 语句中使用,那么它就是 可等待 对象。许多 asyncio API 都被设计为接受可等待对象。
可等待 对象有三种主要类型: 协程, 任务 和 Future .
协程:python中的协程属于 可等待 对象,所以可以在其他协程中被等待
import asyncio
async def nested(): # async def定义一个协程函数,调用它返回的是协程对象
return 42
async def main():
# 直接运行nested()不会得到任何结果,这位这是一个协程对象(协程对象:调用协程函数所返回的对象)
# nested()
# await 后面接的是协程,所以他是一个可等待对象,因此可以在其他协程中被等待
print(await nested()) # will print "42".
asyncio.run(main()) # asyncio.run()运行一个协程
任务: 是用来设置日程以便 并发 执行协程
当一个协程通过 asyncio.create_task() 等函数被打包为一个 任务,该协程将自动排入日程准备立即运行:
import asyncio
async def nested1():
print("nested1")
await asyncio.sleep(0.5)
print("nested1 is finished!")
return 1
async def nested2():
print("nested2")
await asyncio.sleep(0.5)
print("nested2 is finished!")
return 2
async def nested3():
print("nested3")
await asyncio.sleep(0.5)
print("nested3 is finished!")
return 3
async def nested4():
print("nested4")
await asyncio.sleep(0.5)
print("nested4 is finished!")
return 4
async def main():
# Schedule nested() to run soon concurrently
# with "main()".
print("main")
task1 = asyncio.create_task(nested1()) # 使用asyncio.create_task将函数打包成一个任务,该协程将自动排入日程等待运行
task2 = asyncio.create_task(nested2())
task3 = asyncio.create_task(nested3())
task4 = asyncio.create_task(nested4())
await asyncio.sleep(1) # 在main这个协程中,碰到耗时操作,则挂起任务,执行其他任务,即:task1 or task2 or task3 or task4
# "task" can now be used to cancel "nested()", or
# can simply be awaited to wait until it is complete:
print(await task1) # 等待 task1 如果task1中存在耗时操作,则挂起
print(await task2)
print(await task3)
print(await task4)
asyncio.run(main()) # 并发运行这个5个协程,运行最高层级的入口点main函数
nested1
nested2
nested3
nested4
nested1 is finished!
nested2 is finished!
nested4 is finished!
nested3 is finished!
Future对象 Future 是一种特殊的 低层级 可等待对象,表示一个异步操作的 最终结果。
当一个 Future 对象 被等待,这意味着协程将保持等待直到该 Future 对象在其他地方操作完毕。
# 用法:
async def main():
await function_that_returns_a_future_object() # 返回future对象的函数,比如线程池里的submit函数返回的就是一个future对象
# this is also valid:
await asyncio.gather(
function_that_returns_a_future_object(),
some_python_coroutine() # 一些python协程
简单的说,await就是挂起当前任务,去执行其他任务,此时是堵塞的,必须要等其他任务执行完毕才能返回到当前任务继续往下执行,这样的说的前提是,在一个时间循环中有多个task或future,当await右面等待的对象是协程对象时,就没有了并发的作用,就是堵塞等待这个协程对象完成。
协程,又称微线程,纤程。英文名Coroutine。一句话说明什么是线程:协程是一种用户态的轻量级线程。协程的标准定义: 必须在只有一个单线程里实现并发 修改共享数据不需加锁 用户程序里自己保存多个控制流的上下文栈 一个协程遇到IO操作自动切换到其它协程特点:协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。因此,协程能保留上一次调用时的状态(即所有局部状态的一个特定组合),每次过程重...
本文首发于:行者AI
在近期的编码工作过程中遇到了async和await装饰的函数,查询资料后了解到这种函数是基于协程的异步函数。这类编程方式称为异步编程,常用在IO较频繁的系统中,如:Tornado web框架、文件下载、网络爬虫等应用。协程能够在IO等待时间就去切换执行其他任务,当IO操作结束后再自动回调,那么就会大大节省资源并提供性能。接下来便简单的讲解一下异步编程相关概念以及案例演示。
1. 协程简介
1.1 协程的含义及实现方法
协程(Coroutine),也可以被称为微线程,是一种用户态内的.
为什么使用协程?
当多线程或者多进程足够多时,实际上并不能解决性能的瓶颈问题,也就是多线程和多进程对小规模的请求可以提高效率,过多的请求实际上会降低服务资源响应效率,因此协程是更好的解决文案。
什么是协程?
当一个程序遇到阻塞时,如果将这个程序挂起,然后将它的cpu权限拿出来去执行我们的其他程序,执行完后再回过头来执行这些挂起的程序,此时所有非阻塞操作已经执行完毕,最后在一起执行阻塞程序,是不是相当于做了异步。
因此,协程的作用就是检测阻塞的程序,在单进程和单线程的情况下实现异步,相比多线程和多进程
一、事件循环EventLoop
事件循环是asyncio的核心,异步任务的运行、任务完成之后的回调、网络IO操作、子进程的运行,都是通过事件循环完成的。在前一篇文章中,已经提到过,在python3.7中,我们甚至完全不用管事件循环,只需要使用高层API,即asyncio中的方法,我们很少直接与事件循环打交道,但是为了更加熟悉asyncio的运行原理,最好还是了解EventLoop的设计原理。
1、事件循环的创建、获取、设置(上文已经介绍过了)
(1)asyncio.get_running_loop(
在实现异步调用之前我们先进行什么是同步调用和异步调用
同步:是指完成事务的逻辑,先执行第一个事务,如果阻塞了,会一直等待,直到这个事务完成,再执行第二个事务,顺序执行
异步:是和同步相对的,异步是指在处理调用这个事务的之后,不会等待这个事务的处理结果,直接处理第二个事务去了,通过状态、通知、回调来通知调用者处理结果
分析一下,下面的例子:
定义了一个装饰器 async 和 A 、B 两个function 函数
A 里面sleep 10s , 然后打印 a function 字符串
B 里面直接打印 b function 字符串
我们顺序调用两个功能:
Python协程是一种轻量级的多任务并发方法,它可以在单线程中实现并发执行。asyncio是Python 3.4版本之后新增的标准库,提供了对异步IO的支持,可以用于编写高效的异步IO应用程序。asyncio中的协程被称为coroutine,使用async关键字定义。
在asyncio中,可以使用async关键字定义协程,使用await关键字来等待协程执行完成。同时,asyncio提供了事件循环(event loop)来管理协程的执行。事件循环是一个类似于死循环的机制,在其中不断地检查协程的状态并执行它们。
下面是一个简单的使用asyncio的例子:
```python
import asyncio
async def hello():
print("Hello")
await asyncio.sleep(1)
print("World")
loop = asyncio.get_event_loop()
loop.run_until_complete(hello())
在上面的代码中,我们定义了一个协程hello,它先输出“Hello”,然后等待1秒钟,最后输出“World”。我们使用事件循环来执行这个协程。
asyncio还提供了一些常用的工具函数和类,例如:
- asyncio.get_event_loop():获取事件循环对象。
- asyncio.sleep():让协程等待一段时间。
- asyncio.gather():并发执行多个协程。
- asyncio.ensure_future():将协程加入事件循环。
- asyncio.Queue():实现协程之间的消息传递。
使用asyncio可以方便地编写高效的异步IO应用程序。但需要注意的是,在使用asyncio时,应该尽量避免阻塞操作,因为阻塞操作会阻塞事件循环的执行,影响程序的性能。如果需要进行阻塞操作,可以使用asyncio提供的线程池或进程池来进行处理。
北风之神c:
Python多任务—协程(asyncio详解) 一
影子、爱人: