时间:2021-05-23
携程的意义:
共同点:
都是并发操作,多线程同一时间点只能有一个线程在执行,协程同一时间点只能有一个任务在执行;
不同点:
多线程,是在I/O阻塞时通过切换线程来达到并发的效果,在什么情况下做线程切换是由操作系统来决定的,开发者不用操心,但会造成竞争条件 (race condition) ;
协程,只有一个线程,在I/O阻塞时通过在线程内切换任务来达到并发的效果,在什么情况下做任务切换是开发者决定的,不会有竞争条件 (race condition) 的情况;多线程的线程切换比协程的任务切换开销更大;
对于开发者而言,多线程并发的代码比协程并发的更容易书写。
一般情况下协程并发的处理效率比多线程并发更高。
greenlet用于创建协程,switch用于进行协程之间的切换某个协程在执行的过程中可以随时的被其他协程通过switch函数来打断,转而去执行其他协程,当前协程的中断现场会被保留,一旦中断的协程再次获得cpu的执行权首先会恢复现场然后从中断处继续执行这种机制下的协程是同步,不能并发
pip install greenlet
import timeimport greenlet def func1(): print("func11") gr2.switch() time.sleep(1) print("func22") gr2.switch() def func2(): print("func33") gr1.switch() time.sleep(1) print("func44") start = time.time()gr1 = greenlet.greenlet(func1)gr2 = greenlet.greenlet(func2)gr1.switch()end = time.time()print(end - start)pip install gevent
from greenlet import greenletfrom time import sleepdef func1(): print("协程1") sleep(2) g2.switch() print("协程1恢复运行") def func2(): print("协程2") sleep(1) g3.switch()def func3(): print("协程3") sleep(1) g1.switch() if __name__ == '__main__': # 使用greenlet来创建三个协程 g1 = greenlet(func1) g2 = greenlet(func2) g3 = greenlet(func3) # print(g1) g1.switch() # 让协程g1取抢占cpu资源这个过程可以简单理解为:将协程当做任务添加到 事件循环 的任务列表,然后事件循环检测列表中的协程是否 已准备就绪(默认可理解为就绪状态),如果准备就绪则执行其内部代码。
await是一个只能在协程函数中使用的关键字,用于遇到IO操作时挂起 当前协程(任务),当前协程(任务)挂起过程中 事件循环可以去执行其他的协程(任务),当前协程IO处理完成时,可以再次切换回来执行await之后的代码,
await + 可等待对象(协程对象、Future对象、Task对象)
示例1:await+协程对象
import asyncio async def func1(): print("start") await asyncio.sleep(1) print("end") return "func1执行完毕" async def func2(): print("func2开始执行") # await关键字后面可以跟可等待对象(协程对象、Future对象、Task对象) response = await func1() print(response) print("func2执行完毕") asyncio.run(func2())示例2: 协程函数中可以使用多次await关键字
import asyncio async def func1(): print("start") await asyncio.sleep(1) print("end") return "func1执行完毕" async def func2(): print("func2开始执行") # await关键字后面可以跟可等待对象(协程对象、Future对象、Task对象) response = await func1() print(response) response2 = await func1() print(response2) print("func2执行完毕") asyncio.run(func2())Tasks用于并发调度协程,通过asyncio.create_task(协程对象)的方式创建Task对象,这样可以让协程加入事件循环中等待被调度执行。除了使用 asyncio.create_task() 函数以外,还可以用低层级的 loop.create_task() 或 ensure_future() 函数。不建议手动实例化 Task 对象。
本质上是将协程对象封装成task对象,并将协程立即加入事件循环,同时追踪协程的状态。
注意:asyncio.create_task() 函数在 Python 3.7 中被加入。在 Python 3.7 之前,可以改用低层级的 asyncio.ensure_future() 函数。
示例1:
import asyncio async def func(): print(1) await asyncio.sleep(1) print(2) return "func的返回值" async def main(): print(3) # 创建协程,将协程封装到一个task对象中并立即添加到事件循环列表中,等待事件循环去执行,(默认是就绪状态) task1 = asyncio.create_task(func()) # 创建协程,将协程封装到一个task对象中并立即添加到事件循环列表中,等待事件循环去执行,(默认是就绪状态) task2 = asyncio.create_task(func()) # 当执行某协程遇到IO操作时,会自动化切换执行其他任务。 # 此处的await是等待相对应的协程全都执行完毕并获取结果 ret1 = await task1 ret2 = await task2 print(ret1, ret2) asyncio.run(main())示例2:用的还是比较多的
import asyncio async def func(): print(1) await asyncio.sleep(1) print(2) return "func的返回值" async def main(): print(3) # 创建协程,将协程封装到Task对象中并添加到事件循环的任务列表中,等待事件循环去执行(默认是就绪状态)。 # 在调用 task_list = [ asyncio.create_task(func()), asyncio.create_task(func()) ] # 当执行某协程遇到IO操作时,会自动化切换执行其他任务。 # 此处的await是等待所有协程执行完毕,并将所有协程的返回值保存到done # 如果设置了timeout值,则意味着此处最多等待的秒,完成的协程返回值写入到done中,未完成则写到pending中。 done, pending = await asyncio.wait(task_list, timeout=None) print(done) print(pending) asyncio.run(main())示例3:
import asyncio async def func(): print("执行协程函数内部代码") # 遇到IO操作挂起当前协程(任务),等IO操作完成之后再继续往下执行。当前协程挂起时,事件循环可以去执行其他协程(任务)。 response = await asyncio.sleep(2) print("IO请求结束,结果为:", response) coroutine_list = [func(), func()]# 错误:coroutine_list = [ asyncio.create_task(func()), asyncio.create_task(func()) ]# 此处不能直接 asyncio.create_task,因为将Task立即加入到事件循环的任务列表,# 但此时事件循环还未创建,所以会报错。# 使用asyncio.wait将列表封装为一个协程,并调用asyncio.run实现执行两个协程# asyncio.wait内部会对列表中的每个协程执行ensure_future,封装为Task对象。done, pending = asyncio.run(asyncio.wait(coroutine_list))总结:
在程序中只要看到async和await关键字,其内部就是基于协程实现的异步编程,这种异步编程是通过一个线程在IO等待时间去执行其他任务,从而实现并发。
如果是 I/O 密集型,且 I/O 请求比较耗时的话,使用协程。
如果是 I/O 密集型,且 I/O 请求比较快的话,使用多线程。
如果是 计算 密集型,考虑可以使用多核 CPU,使用多进程。
以上就是python中asyncio异步编程学习的详细内容,更多关于python中使用asyncio的资料请关注其它相关文章!
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
1.概述Python中asyncio模块内置了对异步IO的支持,用于处理异步IO;是Python3.4版本引入的标准库。asyncio的编程模型就是一个消息循环
1、说明Python实现异步IO非常简单,asyncio是Python3.4版本引入的标准库,直接内置了对异步IO的支持。asyncio的编程模型就是一个消息循
摘要:简介asyncio可以实现单线程并发IO操作,是Python中常用的异步处理模块。关于asyncio模块的介绍,笔者会在后续的文章中加以介绍,本文将会讲述
我们继续学习Python异步编程,这里将介绍异步Web框架sanic,为什么不是tornado?从框架的易用性来说,Flask要远远比tornado简单,可惜f
前言:因为GIL的限制,python的线程是无法真正意义上并行的。相对于异步编程,其性能可以说不是一个等量级的。为什么我们还要学习多线程编程呢,虽然说异步编程好