美文网首页
11. Asyncio 和 Aiohttp

11. Asyncio 和 Aiohttp

作者: BeautifulSoulpy | 来源:发表于2020-12-29 17:47 被阅读0次

总结:
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()

相关文章

网友评论

      本文标题:11. Asyncio 和 Aiohttp

      本文链接:https://www.haomeiwen.com/subject/hcafoktx.html