总结:
1.IO有关的都是跟系统相关的事情;
2.进程和线程是操作系统支持的功能,由操作系统来进行调度;协程是我们在代码中写的大循环,由它来控制协程对象谁先执行,谁后执行;
1. Asyncio
3.4 版本加入标准库:asyncio 底层基于selectors实现,看似库,其实就是个框架,包含异步IO、事件循环、协程、任务等内容。这个库在不断的演化、性能高效;
协程最早的雏形
import threading, time, multiprocessing
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(3):
next(x)
next(y)
#-----------------------------------------
0
a
1
b
2
c
上例在一个线程内 通过生成器完成了调度,让两个函数都有机会执行,这样的调度不是操作系统的进程、线程完成的,而是用户自己设计的。
这个程序编写:
需要使用yield来让出控制权
需要循环帮助交替执行
2. 事件循环
时间循环是Asyncio提供的核心运行机制
column | column |
---|---|
asyncio.get_event_loop() | 返回一个事件循环对象,是asyncio.BaseEventLoop的实例 |
AbstractEventLoop.stop() | 停止运行事件循环 |
AbstractEventLoop.run_forever() | 一直运行,直到stop() |
AbstractEventLoop.run_until_complete(future) | 运行直至Future对象运行完,返回Future的结果。参数可以是Future类或子类Task的对象。如果是协程对象也会被封装成Task对象; |
AbstractEventLoop.close() | 关闭事件循环 |
AbstractEventLoop.is_running() | 返回事件循环的是否运行 |
AbstractEventLoop.close() | 关闭事件循环 |
AbstractEventLoop.create_task(coro) | 使用协程对象创建任务对象 |
3. 协程
协程不是进程、也不是线程,它是用户空间调度的完成并发处理的方式。它是假并发,交替执行;
进程、线程由操作系统完成调度,而协程是线程内完成调度。它不需要更多的线程,自然也没有多线程切换带来的开销。
协程是非抢占式调度,只有一个协程主动让出控制权,另一个协程才会被调度。
协程也不需要使用锁机制,因为是在同一个线程中执行。
多CPU下,可以使用多进程(真并发)和协程(假并发)配合,既能进程并发又能发挥协程在单线程中的优势。
Python中协程是基于生成器的。
4. 协程的使用
3.4引入asyncio,使用装饰器
早期用法
# 1. 写法1
import threading, time, multiprocessing, asyncio
@asyncio.coroutine
def a():
for x in range(3):
print(x)
yield
def b():
for x in 'abc':
print(x)
yield
loop = asyncio.get_event_loop()
loop.run_until_complete(a())
loop.close()
# 2. 写法2
import threading, time, multiprocessing, asyncio
@asyncio.coroutine
def a():
for x in range(3):
print(x)
yield
loop = asyncio.get_event_loop()
task = loop.create_task(a())
loop.run_until_complete(task)
loop.close()
# 多任务协程
import threading, time, multiprocessing, asyncio
@asyncio.coroutine
def a():
for x in range(3):
print(x)
yield from asyncio.sleep(1)
return 1000
@asyncio.coroutine
def b():
for x in 'abc':
print(x)
yield from asyncio.sleep(2)
def cb(future):
print(3, future, '----------')
print(4, future.result())
loop = asyncio.get_event_loop()
task = loop.create_task(a())
task.add_done_callback(cb) # 回调函数1个参数
print(1, task)
tasks = [task, b()] # 多任务协程
ret = loop.run_until_complete(asyncio.wait(tasks)) # 添加多任务
print(2, task, task.result())
loop.close()
3.5版本开始,Python提供关键字async、await,在语言上原生支持协程。
新语法写法,原生语法支持异步IO
import threading, time, multiprocessing, asyncio
async def a():
for x in range(3):
print(x)
await asyncio.sleep(1)
return 1000
async def b():
for x in 'abc':
print(x)
await asyncio.sleep(2)
def cb(future):
print(3, future, '----------')
print(4, future.result())
loop = asyncio.get_event_loop()
task = loop.create_task(a())
task.add_done_callback(cb) # 回调函数
print(1, task)
tasks = [task, b()] # 多任务协程
ret = loop.run_until_complete(asyncio.wait(tasks)) # 添加多任务
print(2, task, task.result())
loop.close()
async def用来定义协程函数,iscoroutinefunction()返回True。协程函数中可以不包含await、async关键字,但不能使用yield关键字。
如同生成器函数调用返回生成器对象一样,协程函数调用也会返回一个对象称为协程对象,iscoroutine()返回True。
await语句之后是awaitable对象,可以是协程或者实现了 await() 方法的对象。await会暂停当前协程执行,使loop调度其他协程。
import threading, time, multiprocessing, asyncio
async def a():
for x in range(3):
print(x)
await asyncio.sleep(1)
return 1000
async def b():
for x in 'abc':
print(x)
await asyncio.sleep(2)
print(asyncio.iscoroutinefunction(a))
print(asyncio.iscoroutinefunction(b))
#大循环
loop = asyncio.get_event_loop()
tasks = [a(), b()]
results = loop.run_until_complete(asyncio.wait(tasks))
print(results) # 查看结果
loop.close()
5. Aiohttp
HTTP Server
from aiohttp import web
async def indexhandle(request:web.Request):
return web.Response(text=request.path, status=201)
async def handle(request:web.Request):
print(request.match_info)
print(request.query_string) # http://127.0.0.1:8080/1?name=12301
return web.Response(text=request.match_info.get('id', '0000'), status=200)
app = web.Application()
app.router.add_get("/", indexhandle) # http://127.0.0.1:8080/
app.router.add_get("/{id}", handle) # http://127.0.0.1:8080/12301
#app.add_routes([
#web.get('/', indexhandle),
#web.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:8080/2?age=20&name=jerry'
loop = asyncio.get_event_loop()
loop.run_until_complete(get_html(url))
loop.close()
网友评论