python3 asyncio 等待对象_Python-asyncio异步编程

概述:

为什么要学异步非阻塞和asyncio?

异步非阻塞是实现高并发的一种很好的技术手段,除此之外异步框架越来越多,如tonado、fastapi、django 3.x asgi、aiohttp都发展,来提高性能。

内容?

什么是协程

asyncio模块进行异步编程

实战案例

一、协程:

协程不是计算机提供的,是程序员人为创造的。

协程(Coroutine),也可以被称为微线程,是一种用户态内的上下文切换技术。简而言之,其实就是用过一个线程实现代码相互切换执行,例如:

(一)非协程的情况,代码在一个线程中由上至下依次执行

deffunc1():print(1)

...print(2)deffunc2():print(3)

...print(4)

func1()

func2()

(二)实现协程的方式:

greenlet,早期模块

yield关键字

asyncio模块(py3.4后)

async、await关键字(py3.5后,推荐使用)

(三)

1.1 greenlet

1.2  yield关键字

1.3 asycio

在python3.4及之后版本才能用

importasyncio

@asyncio.coroutinedeffunc1():print(1)#网络IO请求:下载一张图片

yield from asynco.sleep(2) #遇到IO耗时操作,自动化切换到task中的其他任务

print(2)

@asyncio.coroutinedeffunc2():print(3)#网络IO请求:下载一张图片

yield from asynco.sleep(2) #遇到IO耗时操作,自动化切换到task中的其他任务print(4)

task=[

asyncio.ensure_future(func1()),

asyncio.ensure_future(func2()),

]

loop=asyncio.get_event_loop()

loop.run_until_complete(asyncio.wait(tasks))

注意:遇到IO阻塞自动切换。不加协程前原来是一张张下,需要4秒,现在遇到IO切换只需要2秒

1.4 asyc & await 关键字

在python3.5及之后的版本引用了这两个关键字,本质上是为了方便引用把@asyncio.coroutine==>async,yield from==>await。

importasyncio

asyncdeffunc1():print(1)#网络IO请求:下载一张图片

await asynco.sleep(2) #遇到IO耗时操作,自动化切换到task中的其他任务

print(2)

asyncdeffunc2():print(3)#网络IO请求:下载一张图片

await asynco.sleep(2) #遇到IO耗时操作,自动化切换到task中的其他任务

print(4)

task=[

asyncio.ensure_future(func1()),

asyncio.ensure_future(func2()),

]

loop=asyncio.get_event_loop()

loop.run_until_complete(asyncio.wait(tasks))

综上:1.1的greenlet是asyncio出来之前实现的协程方式,1.2和1.3都是方便说明1.4的例子,在现实中用greenlet和asyc & await 关键字实现协程较多。

二、协程的意义

在一个线程中如果遇到IO等待时间,线程不会傻傻等,而是利用空闲的时候再去干点其他的事。

案例:下载三张图片(网络IO)

(一)普通方式(同步)

"""pip3 install requests"""

importrequestsdefdownlaod_image(ulr):print("开始下载:",url)#发送网络请求,下载图片

response =requests.get(url)#图片保存到本地文件

file_name = url.rsplit('_')[-1]

with open(file_name,mode= 'wb') as file_object:

file_object.write(response.content)if __name__ =='__main__':

url_list= [

'https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=1819216937,2118754409&fm=26&gp=0.jpg',]for item inurl_list:

download_image(item)

(二)协程方式(异步)

"""下载图片使用第三发模块aiohttp,提前安装:pip3 install aiohttp"""

importaiohttpimportasyncio

asycncdeffetch(session,url):print("发送请求:",url)

async with session.get(url,verify_ssl-False) as response:

content=await response.content.read()

file_name= url.rsplit('_')[-1]

async def main():

async with aiohttp.Clientsession() as session:

url_list = [

'https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=1819216937,2118754409&fm=26&gp=0.jpg',

]

task = [asyncio.create_task(fetch(session,url)) for url in url_list]

await asyncio.await(tasks)

if __name__ =='__main__':

asyncio.run(main())

同步和异步区别:

同步是一个任务执行完才能执行下一个,异步编程是,不等上一个任务完成完,接着进行下一个任务。(二)就是基于协程的方式实现异步编程。当然通过其他的进程池和线程池也同样可以实现异步编程。

三、异步编程

(一)事件循环

理解成为一个死循环,去检测并执行某些代码

#伪代码

任务列表=[任务1,任务2,任务3,。。。]whileTrue:

可执行的任务列表,已完成的任务列表=去任务列表中检查所有的任务,将’可执行‘和’已完成的‘的任务返回for 就绪任务 in可执行的任务列表:

执行已就绪的任务for 已完成的任务 in已完成的任务列表:

在任务列表中的移除 已完成的任务

如果 任务列表 中的任务都已完成,则终止循环

importasyncio#去生成或获取一个事件循环

loop =asyncio.get_event_loop()#将任务放到任务列表中

loop.run_until_complete(任务)

(二)快速上手

协程函数,定义函数时格式:async def 函数名

协程对象,执行协程函数(),得到的是协程对象

ascync deffunc():passresult= func()

注意:执行协程函数,创建的是协程对象,但是函数内部代码不会执行

如果想要运行协程函数内部代码,必须要将协程对象交给事件循环来处理。

importasyncio

asyncdeffunc():print(”快来执行“)

result=func()#python3.7之前的执行方法#loop = asyncio.get_event_loop()#loop.run_until_complete(result)

#python3.7后的执行方法,本质上是将上述两个函数进行了封装

asyncio.run(result)

(三)await

await+可等待对象(如协程对象、Future、Task对象,这些都是IO等待对象)

示例1:

importasyncio

asyncdeffunc():print("来玩呀")#函数执行到这里,因为是await+可等待对象,会跳出该任务,把资源空出来,等response = await asyncio.sleep(2)在继续执行下面的任务

response = await asyncio.sleep(2)print("结束",response)

asyncio.run( func() )

示例2:

importasyncio

asyncdefothers():print("start")

await asyncio.sleep(2)print('end')return "返回值"

asyncdeffunc():print("执行协程函数内部代码")#遇到IO操作挂起当前协程(任务),等待IO操作完成之后在继续往下执行。当前协程挂起时,事件循环可以去执行其他协程(任务)。

response =await others()print("IO请求结束,结果为:",response)

asyncio.run( func() )

执行结果:

执行协程函数内部代码

start

end

IO请求结束,结果为: 返回值

代码执行顺序为:

func() —>print("执行协程函数内部代码")—>response = await others(),判断该对象为IO操作,挂起当前协程,然后执行others()—>print("start")—>await asyncio.sleep(2)

——>2秒后回来执行print('end')——>return '返回值’,把'返回值’返回给response。

response = await others()这里我理解await的作用是,判断后面的时候是可等待对象,如果是话就执行yield from others(),挂起当前协程,执行others()函数。

示例3:一个协程任务中有多个await

import async

async def others():

print("start")

await asyncio.sleep(2)

print('end')

return "返回值"

async def func():

print("执行协程函数内部代码")

#遇到IO操作挂起当前协程(任务),等待IO操作完成之后在继续往下执行。当前协程挂起时,事件循环可以去执行其他协程(任务)。

response1 = await others()

print("IO请求结束,结果为:",response1)

response2 = await others()

print("IO请求结束,结果为:",response2)

asyncio.run( func() )

执行结果为:

执行协程函数内部代码

start

end

IO请求结束,结果为: 返回值

start

end

IO请求结束,结果为: 返回值

(四)Task对象

Tasks are used to schedule coroutines concurrently.

When a coroutine is wrapped into a Task with functions like asyncio.create_task() the coroutine is automatically   scheduled to run soon:

白话:在事件循环中添加多个任务的。

Task用于并发调度协程,通过asyncio.create_task(协程对象)的方式创建Task对象,这样可以让协程加入事件循环中等待被调度执行,除了使用asyncio

高并发是一种场景描述,异步是一种技术手段。

并发强调的是N人干同样的事,要保证不争抢 (lock,atomic,synchronize,volatile, cas)

异步强调的是1/N人干不同的事,不该等的别等 (thread pool, future, async,reactive)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值