一文掌握python协程asyncio(一)

目录

一、什么是协程?

二、异步与await关键字

三、什么是AsyncIO?

四、核心组件

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 定义异步函数。

2、创建事件循环: 使用 asyncio.run()、asyncio.get_event_loop() 或者 asyncio.new_event_loop() 创建或获取事件循环。

1)asyncio.run()

 2)asyncio.get_event_loop()

3)asyncio.new_event_loop()

请注意,通常推荐使用更高层次的 API 如 asyncio.run() 来管理事件循环,因为它会自动处理事件循环的创建、运行以及最后的清理工作,使得代码更简洁且易于理解。只有在确实需要自定义事件循环生命周期管理时,才应考虑直接使用 asyncio.new_event_loop()。

总结

3、调度协程: 通过 asyncio.create_task() 将协程转换为一个可以在事件循环中并发执行的任务。使用它可以让协程并发执行,而不阻塞主线程。

4、事件循环运行

1)asyncio.run()

2)loop.run_until_complete() 

3)loop.run_forever()

六、进阶功能

1、并发执行多个任务: 使用 asyncio.gather() 或 asyncio.wait() 并发执行多个任务。

1)asyncio.gather()是启动并等待一组Future或协程完成的便捷方法。它能够并发地执行多个任务,并且可以返回所有任务的结果(如果有返回值的话),或者在遇到第一个错误时立即停止并传播该异常。

2)使用asyncio.wait()

2、超时处理和取消任务: 可以为任务设置超时时间,或主动取消任务。

1)超时处理

2)取消任务

3、信号和异常处理: 处理外部信号(如SIGINT)以及在协程中捕获和处理异常。

1)信号处理

2)异常处理

4、并发限制:   控制同时运行的协程数,避免资源耗尽、服务过载。

1)使用Semaphore

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()
  • 16
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值