python浅学笔记20-异步IO

学习文档 from https://www.liaoxuefeng.com

异步IO

cpu速度远远快于 网路 磁盘 IO
在一个线程里,IO会阻塞其它代码的执行。为了不阻塞,就要用多线程或多进程,虽然并发可以解决这个问题,但是系统不能无上限的增加线程,系统切换线程的开销也很大
另一种解决问题的方法异步IO,cpu负责代码的执行,IO操作由IO设备执行,代码负责打开一个IO操作,并监听IO的进度。
异步模型需要一个消息循环,主线程不断地重复‘读取消息-处理消息’这一过程。
消息模型早就应用在桌面应用程序中了,一个GUI程序的主线程就负责不停的读取消息并处理消息。所有的键盘、鼠标等消息都被发送到GUI程序的消息队列中。
GUI线程处理消息必须非常迅速,如果出问题,处理时间过长,会让人感到卡顿,程序看上去停止响应。
同步IO,主线程遇到IO操作,就会挂起,异步IO,主线程遇到IO操作,会发一个IO请求,在轮询消息时,如果IO操作完成,会在消息队列中有其完成的消息,这是才会处理IO完成阶段的代码。
异步IO模型 能大大提升IO密集型应用程序的多任务处理能力。
异步IO到底怎么实现的呢?像游戏引擎,就是每一帧处理很多东西,其中就有网络操作。

协程 Coroutine

又名:微线程 纤程,在Lua广泛使用。
一个函数执行,可以中断,然后执行其他函数(并不是函数调用),还可以返回继续执行(不是其他函数返回)
比多线程的优势:1.切换没有线程那么大的开销,2.不需要锁机制,不存在同时写变量的问题
多进程 + 协程,可以充分利用多核,
Python的协程是由generator实现的。
不仅可以用for迭代,还可以用next()获取yield返回的下一个值。
生产者-消费者模型
generator.send(None)可以启动生成器且generator用send发送协程的继续开始,并返回下一个yield值
close()可以关闭一个协程。

asyncio

Python3.4版本内置了对异步IO的支持。
asyncio的编程模型就是一个消息循环。EventLoop,把需要执行的协程放到这个loop中执行,就实现了异步IO。多个协程可以并发执行。

async/await

Python3.5 引入了新语法async 和 await,可以让coroutine代码更简洁易读。
只需要把3.4的 @asyncio.coroutine 替换为 async,并从注解位置换成修饰def,把yield from替换为await

aiohttp

asyncio 实现了TCP\UDP\SSL等协议
aiohttp则是基于asyncio实现的HTTP框架
pip install aiohttp

#提醒api过期
#1.web.Application(loop = loop) loop关键字过期,去掉
#2.app.make_handler() 过期,使用 web.AppRunner
#输入网址就下载一个文件,而不是网页
#response header,Content-Type: application/octet-stream 需要这是一下内容类型才能显示网页

import asyncio
from aiohttp import web

async def index(request):
    await asyncio.sleep(0.5)
    return web.Response(body=b'<h1>Index</h1>',content_type = 'text/html')

async def init():
    app = web.Application()
    app.router.add_route('GET','/',index)
    runner = web.AppRunner(app)
    await runner.setup()
    site = web.TCPSite(runner,'127.0.0.1',9000)
    await site.start()
    print('server start at http://127.0.0.1:9000...')

loop = asyncio.get_event_loop()
loop.run_until_complete(init())
loop.run_forever()

run_until_complete方法:Run the event loop until a Future is done.
run_forever方法:Run the event loop until stop() is called.

猜测server会异步接受所有网络请求(包括网络IO的开始到完成,完成后根据url在loop时触发),run_forever不停的轮询loop,而app.router.add_route在这个loop里添加了监听事件,当事件触发时,执行异步回调,查看api发现,app是一个baseRunner,runner 是一个AppRunner,在setup时,做了_make_handler操作,site.start()中loop.create_server()建立了server。
唯一的问题是,我们的代码里有get_event_loop,make handler时有get_event_loop,create server时有get_event_loop这3个get到的loop是否是同一个loop呢?
访问了下aiohttp官网,发现好多可以看的内容,比如官方server的实现

from aiohttp import web

async def handle(request):
    name = request.match_info.get('name', "Anonymous")
    text = "Hello, " + name
    return web.Response(text=text,content_type = 'text/html')

app = web.Application()
app.add_routes([web.get('/', handle),
                web.get('/{name}', handle)])

web.run_app(app,host = '127.0.0.1',port = 9000)

都不用引入asyncio,是不是清爽了很多
我更喜欢使用另一种注解的方式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值