JAVA和Nginx 教程大全

网站首页 > 精选教程 正文

python异步IO高并发之aiohttp python标准库

wys521 2024-10-24 16:52:08 精选教程 45 ℃ 0 评论

异步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

待研究问题

  1. flask项目改造为aiohttp能否只改造路由和异步request部分?
  2. 使用aiohttp的知名项目有哪些?还是选择tarnado比较稳妥?

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表