asyncio
3.4版本加入标准库
asyncio底层基于selectors实现,看似库,其实就是个框架,包含异步IO、事件循环、协程、任务等内容
问题的引出
def a():
for x in range(3):
print(x)
def b():
for x in "abc":
print(x)
a()
b()
# 运行结果一定是
0
1
2
a
b
c
这是一个串行的程序,单线程中根本没有做任何
能否并行?
import threading
import time
def a():
for x in range(3):
time.sleep(0.001)
print(x)
def b():
for x in "abc":
time.sleep(0.001)
print(x)
threading.Thread(target=a, name='a').start()
threading.Thread(target=b, name='b').start()
# 运行结果
0
a
1
b
2
c
生成器版本
def a():
for x in range(3):
print(x)
yield
def b():
for x in "abc":
print(x)
yield
x = a()
y = b()
for i in range(5):
next(x)
next(y)
上例在一个线程内通过生成器完成了调度,让两个函数都有机会执行,这样的调度不是操作系统的进程、线程完成的,而是用户自己设计的
这个程序编写
需要使用yield来让出控制权
需要循环帮助交替执行
事件循环
事件循环是asyncio提供的核心运行机制
asyncio.get_event_loop() | 返回一个事件循环对象,是asyncio.BaseEventLoop的实例 |
---|---|
AbstractEventLoop.stop() | 停止运行事件循环 |
AbstractEventLoop.run_forever() | 一直运行,直到stop() |
AbstractEventLoop.run_until_complete(future) | 运行直至Future对象运行完 |
AbstractEventLoop.close() | 关闭事件循环 |
AbstractEventLoop.is_running() | 返回事件循环的是否运行 |
AbstractEventLoop.close() | 关闭事件循环 |
协程
- 协程不是进程,也不是线程,它是用户空间调度的完成并发处理的方式
- 进程、线程由操作系统完成调度,而协程是线程内完成调度。它不需要更多的线程,自然也没有多线程切换带来的开销
- 协程是非抢占式调度,只有一个协程主动让出控制权,另一个协程才会被调度
- 协程也不需要使用锁机制,因为是在同一个线程中执行
- 多CPU下,可以使用多进程和协程配合,既能进程并发又能发挥协程在单线程中的优势
- Python中协程是基于生成器的
协程的使用
3.4引入asyncio,使用装饰骑
import asyncio
@asyncio.coroutine
def sleep(x): # 协程函数
for x in range(3):
print('sleep {}'.format(i))
yield from asynio.sleep(x)
loop = asyncio.get_event_loop()
loop.run_until_complete(sleep(c))
loop.close()
将生产器函数转换成协程函数,就可以在事件循环中执行了
3.5版本开始,Python提供关键字async、await,在语言上原生支持协程
import asyncio
async def sleep(x):
for i in range(3):
print('sleep {}'.format(i))
await asyncio.sleep(x)
loop = asyncio.get_event_loop()
loop.run_until_complete(sleep(3))
loop.close()
async def用来定义协程函数,iscoroutinefunction()返回True。协程函数中可以不包含await、async关键字,但不能使用yield关键字
如同生成器函数调用返回生成器对象一样,协程函数调用也会返回一个对象为协程对象,iscoroutine()返回True
再来做个例子
import asyncio
import threading
async def sleep(x):
for i in range(3):
print('sleep {}'.format(i))
await asyncio.sleep(x)
async def showthread(x):
for i in range(3):
print(threading.enumerate())
await asyncio.sleep(2)
loop = asyncio.get_event_loop()
tasks = [sleep(3), showthread(3)]
loop.run_until_complete(asynio.wait(tasks))
loop.close()
# 协程版本
import asyncio
import threading
@asyncio.coroutine
def a():
for x in range(3):
print('a.x', x)
yield
@asyncio.coroutine
def b():
for x in 'abc':
print('b.x', x)
yield
print(asyncio.iscoroutinefunction(a))
print(asyncio.iscoroutinefunction(b))
# 大循环
loop = asyncio.get_event_loop()
tasks = [a(), b()]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()
aiohttp库
安装
pip install aiohttp
开发
HTTP Server
from aiohttp import web
async def indexhandle(request: web.Request):
return web.Response(text=request.path, status=200)
async def handle(request: web.Request):
print(request.match_info)
print(request.query_string)
return web.Response(text=request.match_info.get('id', '0000'), status=200)
app = web.Application()
app.router.add_get('/', indexhandler)
app.router.add_get('/{id}', handle)
web.run_app(app, host='0.0.0.0', port=9977)
HTTP Client
import asyncio
from aiohttp import ClientSession
async def get_html(url: str):
async with ClientSession() as session:
async with session.get(url) as res:
print(res.status)
print(await res.text())
url = 'http://127.0.0.1/ziroom-web/'
loop = asyncio.get_event_loop()
loop.run_until.complete(get_html(url))
loop.close()