Python中asyncio库的使用
1、asyncio
3.4版本以后加入标准库。
Asyncio底层基于selectors,看似库,其实就是框架,包含异步IO、时间循环、协程、任务等内容。
def a(x=3):
for x in range(x):
print(x)
def b(x=3):
for x in range(x):
print(x)
a()
b()
上例子中函数调用是串行,不是并行。可以利用方法进行改变。
1)利用生成器函数
def a(x=3):
for x in range(x):
print(x)
yield
def b(x=3):
for x in range(x):
print(x)
yield
x1 = a()
y = b()
for i in range(3):
next(x1)
next(y)
2)多线程
import time
import threading
def a(x=3):
for x in range(x):
time.sleep(1)
print(x)
def b(x=3):
for x in range(x):
time.sleep(1)
print(x)
threading.Thread(target=a,name='a').start()
threading.Thread(target=b,name='b').start()
3)利用multiprocessing库,也是多线程
import time
import multiprocessing
def a(x=3):
for x in range(x):
time.sleep(1)
print(x)
def b(x=3):
for x in range(x):
time.sleep(1)
print(x)
if __name__ == '__main__':
multiprocessing.Process(target=a,name='a').start()
multiprocessing.Process(target=b,name='b').start()
生成器函数,真并行。
生成器在用户空间完成的切换。调度不是操作系统的进程、线程。两个函数都有机会执行。
Yield本意是让出,让出线程执行的权限,让出控制权限。
必须有循环,没有循环就不能够交替执行。
2、事件循环
事件循环是asyncio提供的核心运行机制。
Column |
Column |
Asyncio.get_event_loop() |
返回一个事件循环对象,是asyncio.Baseeventloop的实例 |
Abstracteventloop.stop() |
停止运行事件循环 |
Abstracteventloop.run_forever() |
一直运行直到stop() |
Abstracteventloop.run_until_complete(future) |
运行直至future对象运行完 |
Abstracteventloop.close() |
关闭事件循环 |
Abstracteventloop.is_running() |
返回事件循环的是否运行 |
3、协程
1)不是进程,也不是线程,是用户空间调度的完成并发处理的方式。是在用户空间内部完成的。
2)进程、线程是操作系统完成调度,而协程是线程内完成调度,不需要更多的线程,也没有多线程切换带来的开销。
3)协程是非抢占式调度,只有协程主动让出控制权,另一个协程才会被调度。
4)协程不需要使用锁机制,因为是在同一个线程中执行的。
5)多CPU下,可以使用多进程和协程配合下,既能进程并行又能发挥协程在单线程中的优势。
6)Python中协程是基于生成器的。
线程和进程是操作系统内完成的。
4、协程的使用
Coroutine协程;
await:等待,相当于yield form。
import asyncio
@asyncio.coroutine
def sleep(x):
for i in range(3):
print('sleep {}'.format(i))
yield from asyncio.sleep(3)
loop = asyncio.get_event_loop()
loop.run_until_complete(sleep(3))
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()
sleep 0
sleep 1
sleep 2
Async 得分用来定义协程函数,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(asyncio.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 i in range(3):
print('b.x',i)
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()
Tasks,任务列表。
下面是执行的;
新的语法。
5、tcp echo server举例
import asyncio
async def handle(reader,writer):
while True:
data = await reader.read(1024)
print(dir(reader))
print(dir(writer))
client = writer.get_extra_info('peername')
message = '{}you mesg {}'.format(client,data.decode()).encode()
writer.writer(message)
await writer.drain()
loop = asyncio.get_event_loop()
ip = '127.0.0.1'
port = 8080
crt = asyncio.start_server(handle,ip,port,loop=loop)
server = loop.run_until_complete(crt)
print(server)
try:
loop.run_forever()
except KeyboardInterrupt:
pass
finally:
server.close()
loop.close()
6、aiohttp 库:
安装pip install aiohttp
写http服务。
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)
return web.Response(text=request.match_info.get('id','0000'),status=200)
app = web.Application() #默认端口和地址。
app.router.add_get('/',indexhandle) #请求来了找处理函数。
app.router.add_get('/{id}',handle)
web.run_app(app,host='127.0.0.1',port=8080)
======== Running on http://127.0.0.1:8080 ========
(Press CTRL+C to quit)
<MatchInfo {'id': 'favicon.ico'}: <ResourceRoute [GET] <DynamicResource /{id}> -> <function handle at 0x00000044F1494730>>
import asyncio
from aiohttp import ClientSession
async def get_html(url:str):
async with ClientSession() as session: #with是上下文
async with session.get(url) as res: #session是保持会话,get得到一个网页。
print(res.status) # 打印状态码
print(await res.text()) # 提取文本内容。首页都是同步加载,里面异步加载请求。
url = 'http://www.magedu.com'
loop = asyncio.get_event_loop()
loop.run_until_complete(get_html(url))
loop.close()
200
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
<meta name="renderer" content="webkit">
<meta name="viewport" content="initial-scale=1.0,user-scalable=no,maximum-scale=1,width=device-width">
<meta name="format-detection" content="telephone=no">