目录
4、Future:是异步计算的一个抽象,代表一个可能还没有完成的计算。它是任务的底层实现细节,但通常开发者直接与任务交互更多。
2、创建事件循环: 使用 asyncio.run()、asyncio.get_event_loop() 或者 asyncio.new_event_loop() 创建或获取事件循环。
3、调度协程: 通过 asyncio.create_task() 将协程转换为一个可以在事件循环中并发执行的任务。使用它可以让协程并发执行,而不阻塞主线程。
1、并发执行多个任务: 使用 asyncio.gather() 或 asyncio.wait() 并发执行多个任务。
2、超时处理和取消任务: 可以为任务设置超时时间,或主动取消任务。
3、信号和异常处理: 处理外部信号(如SIGINT)以及在协程中捕获和处理异常。
4、并发限制: 控制同时运行的协程数,避免资源耗尽、服务过载。
2)BoundedSemaphore (与Semaphore类似,打印信息相同)
一、什么是协程?
协程,简而言之,是一种可以挂起和恢复执行的函数。与传统线程不同,协程是在同一线程内协作执行,无需切换上下文,因此开销极小。这使得协程非常适合处理大量并发的I/O密集型任务,如网络请求、文件读写等。
协程(Coroutine)的设计初衷是为了解决在单一线程内执行多个任务时的效率问题,尤其是对于I/O密集型任务,它们能够通过非阻塞的方式实现高并发,而无需创建额外的线程或进程。因此,协程的数量理论上可以非常庞大,受限于系统内存和程序设计,而非CPU线程数。
二、异步与await关键字
在Python中,定义一个协程函数需要使用async def
关键字,而调用协程函数时需搭配await
关键字。await
用于等待一个异步操作完成并返回结果,期间允许其他协程执行,实现了非阻塞式的并发处理。
三、什么是AsyncIO?
asyncio
是 Python 的一个标准库,它引入了异步 I/O,事件循环,任务和协程的支持,使得编写并发代码变得更加简单和直接,尤其适合处理大量的I/O密集型操作,如网络请求、文件读写等,而无需创建多个线程或进程。
四、核心组件
-
1、事件循环(Event Loop): 是
asyncio
的心脏,负责调度和运行所有的异步任务。它会持续运行,直到没有更多的任务可以执行。事件循环监视和管理异步任务的执行状态,比如I/O操作、定时器等,并在操作完成时恢复相关任务的执行。 -
2、协程(Coroutine): 在Python中,协程是使用
async def
定义的函数。它们是可以挂起和恢复执行的函数,允许非阻塞式的并发操作。通过在协程中使用await
关键字,可以等待一个异步操作完成而不阻塞整个程序。 -
3、任务(Task): 代表了事件循环中的一个协程,它是可被追踪和管理的单元。通常使用
asyncio.create_task()
或asyncio.ensure_future()
来创建任务。任务可以被取消,也可以有返回值。 -
4、Future:是异步计算的一个抽象,代表一个可能还没有完成的计算。它是任务的底层实现细节,但通常开发者直接与任务交互更多。
五、基本使用步骤
1、定义协程: 使用 async def
定义异步函数。
async def my_coroutine():
# 异步操作
await asyncio.sleep(1)
print("Coroutine finished")
2、创建事件循环: 使用 asyncio.run()
、asyncio.get_event_loop()
或者 asyncio.new_event_loop()
创建或获取事件循环。
1)asyncio.run()
这是最推荐的启动事件循环的方式,特别是对于简单的脚本或应用。asyncio.run()
会自动处理事件循环的创建、运行以及最后的清理工作(包括关闭事件循环)。使用它非常简洁:
import asyncio
async def main():
print("Hello")
await asyncio.sleep(1)
print("World")
asyncio.run(main())
2)asyncio.get_event_loop()
asyncio.get_event_loop()
用于获取当前线程的事件循环。如果当前线程没有事件循环,它会创建一个新的事件循环并返回。这种方式在需要手动控制事件循环的生命周期时很有用,但需要注意,当事件循环不再需要时,应该显式调用loop.close()
来关闭它。
import asyncio
async def my_coroutine():
print("Coroutine started")
await asyncio.sleep(1)
print("Coroutine finished")
def main():
# 获取当前线程的事件循环,如果不存在则创建一个
loop = asyncio.get_event_loop()
print("Event loop created:", loop)
try:
# 将协程包装成一个任务并安排到事件循环中执行
task = loop.create_task(my_coroutine())
print("Task created and scheduled:", task)
# 运行事件循环直到所有任务完成
print("Starting event loop...")
loop.run_until_complete(task)
except Exception as e:
print("Caught an exception:", e)
finally:
# 清理工作,关闭事件循环
print("Closing event loop...")
loop.close()
print("Event loop closed.")
if __name__ == "__main__":
main()
在这个例子中,首先获取当前线程的事件循环并打印出来,接着创建一个协程任务并安排它在事件循环中执行。事件循环的创建、任务的安排、启动以及最终的关闭过程,这是整个事件循环的工作流程。
3)asyncio.new_event_loop()
asyncio 库中用来手动创建一个新的事件循环实例的方法。在大多数情况下,不直接需要调用这个方法,因为当你使用 asyncio.run()
, asyncio.create_task()
, 或者在异步函数中使用 await
时,asyncio 会自动管理事件循环。
然而,如果需要对事件循环有更细粒度的控制,例如在一些复杂的多线程或多进程应用中,可能需要手动创建并使用事件循环。下面是一个简单的示例,展示了如何手动创建并使用一个新的事件循环:
import asyncio
def main():
# 手动创建一个新的事件循环
new_loop = asyncio.new_event_loop()
try:
# 设置当前线程的事件循环为新创建的循环
asyncio.set_event_loop(new_loop)
# 在新事件循环中执行异步代码
new_loop.run_until_complete(async_example())
finally:
# 清理工作,关闭事件循环
new_loop.close()
async def async_example():
print("Starting an asynchronous task...")
await asyncio.sleep(1)
print("Asynchronous task finished.")
if __name__ == "__main__":
main()
请注意,通常推荐使用更高层次的 API 如 asyncio.run()
来管理事件循环,因为它会自动处理事件循环的创建、运行以及最后的清理工作,使得代码更简洁且易于理解。只有在确实需要自定义事件循环生命周期管理时,才应考虑直接使用 asyncio.new_event_loop()
。
总结
- 对于大多数情况,特别是简单的异步应用,推荐使用
asyncio.run()
,因为它是最简洁且自动化的。 - 当需要对事件循环有更多的控制,比如在复杂应用中管理多个任务的调度时,可以使用
asyncio.get_event_loop()
。 - 在多线程环境下,或明确需要创建新事件循环的场景下,使用
asyncio.new_event_loop()
。