ITPub博客

首页 > 应用开发 > > python异步IO高并发之aiohttp

python异步IO高并发之aiohttp

作者:25minutes 时间:2019-11-22 10:38:55 0 删除 编辑

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/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2019-07-17

  • 博文量
    336
  • 访问量
    14897