首页 > 应用开发 > > python异步IO高并发之aiohttp
Python与智能应用
异步io的优势
传统web应用的一大缺点是,遇到io只能阻塞,等待处理完后再返回,在此期间,无法处理其他的请求。严重降低了系统的并发能力。而异步io则应用而生,本文将从协程、asyncio、aiohttp这三个方面介绍异步io的使用。
协程
协程和线程的区别
协程,即协作式程序,其思想是,一系列互相依赖的协程间依次使用CPU,每次只有一个协程工作,而其他协程处于休眠状态。协程实际上是在一个线程中,只不过每个协程对CPU进行顺序分时使用。任务执行顺序用户可控。
线程,多线程共享进程中的资源,通过全局GIL锁来平均分配CPU,在不同线程中不断切换执行任务,任务执行顺序用户不能控制。
asyncio
asyncio是Python 3.4版本引入的标准库,直接内置了对异步IO的支持。同时从Python 3.5开始引入了新的语法async和await,让协程的代码更简洁易读。基本用法如下:
import asyncio
async def hello():
print("Hello world!")
r = await asyncio.sleep(1)
print("Hello again!")
# 获取EventLoop:
loop = asyncio.get_event_loop()
# 执行coroutine
loop.run_until_complete(hello())
loop.close()
使用步骤:
1.利用async关键字定义协程,利用await做异步io切换
2.获取eventloop
3.执行协程,等待所有协程执行完毕
线程和协程执行效率PK
这里我们测试1000个协程和线程执行时间耗时(模拟io时间为1s),代码如下:
from threading import Thread
import time
import asyncio
async def hello():
r = await asyncio.sleep(1)
pre_time = time.time()
loop = asyncio.get_event_loop()
tasks = [hello() for x in range(1000)]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()
print('1000个协程耗时:', time.time() - pre_time, 's')
def hello():
time.sleep(1)
pre_time = time.time()
threads = [Thread(target=hello) for x in range(1000)]
for x in threads:
x.start()
for x in threads:
x.join()
print('1000个线程耗时', time.time() - pre_time, 's')打印结果如下:
1000个协程耗时: 1.0314579010009766 s
1000个线程耗时 1.1242129802703857 s
显然,协程效率大于线程,若继续增大任务数目到10000呢?
打印显示:
10000个协程耗时: 1.2555210590362549 s
_start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
可以看出,多个协程切换时间依旧很小,而线程由于数目太多已经挂了,在这种io高并发场景中,协程完胜。
aiohttp
和asyncio的区别是:
asyncio实现了TCP、UDP、SSL等协议,aiohttp则是基于asyncio实现的HTTP框架。
在python中其他知名的异步io框架还有:
Tornado:异步非阻塞IO的Python Web框架,最新版本的异步协程是基于Python内置的asyncio来实现(老版本用装饰器实现异步)
Pulsar:Python的事件驱动并发框架
Diesel:基于Greenlet的事件I/O框架
安装:
pip install aiohttp
基本使用如下:
import asyncio
from aiohttp import web
async def index(request):
await asyncio.sleep(0.5)
return web.Response(body=b'<h1>Index</h1>')
async def hello(request):
await asyncio.sleep(0.5)
text = '<h1>hello, %s!</h1>' % request.match_info['name']
return web.Response(body=text.encode('utf-8'))
async def init(loop):
app = web.Application(loop=loop)
app.router.add_route('GET', '/', index)
app.router.add_route('GET', '/hello/{name}', hello)
srv = await loop.create_server(app.make_handler(), '127.0.0.1', 8000)
print('Server started at http://127.0.0.1:8000...')
return srv
loop = asyncio.get_event_loop()
loop.run_until_complete(init(loop))
loop.run_forever()官方建议部署方式为:
nginx+supervisor,此种部署方式性能最佳
具体使用可以参考官方文档:
https://github.com/aio-libs/aiohttp
待研究问题
flask项目改造为aiohttp能否只改造路由和异步request部分?
使用aiohttp的知名项目有哪些?还是选择tarnado比较稳妥?官方建议部署方式为:
nginx+supervisor,此种部署方式性能最佳
具体使用可以参考官方文档:
https://github.com/aio-libs/aiohttp
待研究问题
flask项目改造为aiohttp能否只改造路由和异步request部分?
使用aiohttp的知名项目有哪些?还是选择tarnado比较稳妥?
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/4328/viewspace-3161061/ ,如需转载,请注明出处,否则将追究法律责任。