有网友碰到这样的问题“异步框架Asyncio解读”。小编为您整理了以下解决方案,希望对您有帮助:
解决方案1:
Asyncio 是 Python 的异步框架,提供高效率的异步组件功能,适用于网络和 Web 服务器、数据库连接库、分布式任务队列等场景。它包含两种 API:高阶 API 和低阶 API,后者偏底层,更适合网络框架工程师使用。
理解异步开发的基础概念是关键。Asyncio 通过在一个线程中并行运行多个协程,控制其运行状态和顺序来实现高效运行。Event loop 在主线程中运行,轮询并执行满足运行条件的协程任务,特别是需要 IO 操作的场景,如网络连接、数据读取等,通过支持异步的第三方库如 aiohttp 实现。
在使用网页请求时,通常采用包 requests,其使用的是 blocking sockets,与 asyncio 结合会直接堵塞主线程。因此,在异步框架中使用 aiohttp。aiohttp 可设置超时时间,若超时会抛出异常。
若存在没有 no-blocking API 的情况,可以考虑使用多线程包,在不同线程中运行 blocking API。在多核系统中,建议线程数超过核数 4 个,但需注意线程数选择,以避免过载。
定义协程任务使用 async/await 语法,以正常的同步代码方式编写,函数名前添加 async 关键字,存在“异步”(需要等待)的代码前添加 await 关键字。运行协程时,启动 event loop,有多种方式:
1)asyncio.run(main()),与同步调用效果相似,总体运行时间无明显节省,非并行运行。
2)asyncio.create_task(),定义为协程任务,使用 await 启动(必须使用 await 启动,否则任务不会执行),总体运行时间节省。
3)asyncio.TaskGroup(),使用任务组启动协程任务,节省运行时间。
4)asyncio.gather(),依次运行协程任务,等待所有任务完成。设置 return_exceptions=True 时,即使有线程报错,报错信息作为返回值,不影响其他线程完成任务。
注意:使用 asyncio 默认的 event loop,可自定义或选择第三方开发的 event loop,如 uvloop,比默认的 event loop 更快。使用 asyncio.set_event_loop 获得自定义 event loop,asyncio.get_running_loop() 可在不同 thread 中调用。
定义协程任务,使用 create_task 完成。避免任务运行中途被垃圾回收,使用代码确保。转让运行权力给其他协程,让当前任务等待。不允取消任务,使用 shield。任务运行时间,超时报错,调整到期时间,使用 reschedule。获取当前协程任务执行情况,pending 返回集合为空。
返回值为 done 和 pending,done 为已完成的协程 Task,pending 为超时未完成的协程。参数 return_when 指定返回条件,timeout 指定结果截至时间。
使用 asyncio.current_task() 或 asyncio.all_tasks() 获得当前运行任务列表。启动协程任务并遍历完成结果,一旦任务完成,可立即获得结果,继续执行操作,API 可设置 timeout 参数。
为协程添加回调函数,即协程结束后调用另一个任务。使用 add_done_callback。注意 asyncio 不是线程安全,可使用 asyncio.lock() 对公共资源加锁操作。
协程间需要传递信号协作,使用 event 实现。当某事满足条件后,发送事件信号。asyncio.Condition 结合 event 和 lock。
Semaphore 实现内部计数器,acquire 计数器减一,约束同时运行的协程数量,避免 CPU 超负荷。若需等待任务数量,例如必须有 3 个在等待,使用 asyncio.Barrier。
Asyncio 实际上单线程执行多个任务,但可通过 to_thread 方法将任务分配到新线程执行(适用于 IO 多的任务,CPU 任务多的场景需第三方模块支持)。
从其他线程调用任务到事件循环线程,使用 asyncio.run_coroutine_threadsafe。
遇到大量 CPU 计算场景时,创建 Python 进程池,用于并行运行函数。在异步框架中,可使用 gather、run_in_executor 使用进程池;或使用 loop.run_in_executor 使用线程池。
其他 Asyncio API 包括:Streams 高级异步/等待 API,用于处理网络连接,允许不使用回调或低级协议和传输发送和接收数据。Queue 队列,用于管理并行任务,确保执行顺序,通过 asyncio.Queue 管理任务队列,使用 queue.put_nowait、queue.get()、queue.task_done()、queue.join() 操作。
使用 debug mode,asyncio.run(coroutine(), debug=True),当协程或任务运行时间超过 100 毫秒时,可获取有用日志信息。
Copyright © 2019- kuangzang.com 版权所有
违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务