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">

posted @ 2018-11-12 23:31  Python爱好者666  阅读(4588)  评论(0编辑  收藏  举报