温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

48异步编程_asyncio_aiohttp

发布时间:2020-06-11 20:22:42 来源:网络 阅读:278 作者:chaijowin 栏目:编程语言

 

目录

asyncio. 1

事件循环:... 1

协程:... 2

aiohttp... 4

 

 

 

asyncio

异步io3.4version加入标准库;

asyncio底层基于selectors实现,看似库,其实是个框架,包含异步IO、事件循环、协程、任务等内容;

 

例:

def a():

    for x in range(3):

        time.sleep(0.001)   #生产上不能加此句,仅在多线程下做实验用

        print('a.x', x)

 

def b():

    for x in 'abc':

        time.sleep(0.001)

        print('b.x', x)

 

# a()   #串行,两件事如果有因果关系才需要串行,否则并行要好

# b()

 

# threading.Thread(target=a).start()   #多线程下,由OS控制;输出会乱

# threading.Thread(target=b).start()

 

if __name__ == '__main__':

    multiprocessing.Process(target=a).start()   #真正的同时进行,由OS控制

    multiprocessing.Process(target=b).start()

 

 

事件循环:

asyncio提供的核心运行机制;

 

loop = asyncio.get_event_loop()   #返回一个事件循环对象,是asyncio.BaseEventLoop的实例;

loop.stop()asyncio.AbstractEventLoop.stop()   #停止运行事件循环

loop.run_forever()asyncio.AbstractEventLoop.run_forever()   #一直运行,直到stop

loop.run_until_complete(future)asyncio.AbstractEventLoop.run_until_complete(future)   #运行直至Future对象运行完

loop.close()asyncio.AbstractEventLoop.close()   #关闭事件循环

loop.is_running()asyncio.AbstractEventLoop.is_running()   #返回事件循环是否运行

 

 

协程:

例:

协程,有返回值None,但没有用;

由自己控制(类似于并发的控制),与多线程、多进程没关系;

在线程内通过生成器完成了调度,让两个函数几乎都有在执行,这样的调度不是OS的进程、线程完成的,而是用户自己设计的;

编写此程序,要使用yield来让出控制权,要用循环帮助执行;

def a():

    for x in range(3):

        time.sleep(0.001)

        print('a.x', x)

        yield

 

def b():

    for x in 'abc':

        time.sleep(0.001)

        print('b.x', x)

        yield

 

m = a()

n = b()

for _ in range(3):

    next(m)

    next(n)

 

不是进程,也不是线程,它是用户空间调度完成并发处理的方式

进程、线程由OS完成调度,而协程是线程内完成调度,它不需要更多的线程,自然也没有多线程切换带来的开销;

协程是非抢占式调度(串行),只有一个协程主动让出控制权,另一个协程才会被调度;

协程也需要使用锁机制,因为是在同一个线程中执行;

cpu下,可使用多进程+协程配合,既能进程并发又能发挥协程在单线程中的优势;

py中协程是基于生成器的;

 

3.5version开始,py提供关键字asyncawait,在语言上原生支持协程,支持async defasync withasync for

async def用来定义协程函数,调用后即是协程对象(同生成器函数、生成器对象),协程函数中可以不包含awaitasync关键字,不能使用yield关键字;

 

asyncio.iscoroutinefunction(sleep)   #判断是否是协程函数

asyncio.iscoroutine(thread)   #判断是否是协程对象

 

例:

@asyncio.coroutine   #使用装饰器,3.4ver用法

def sleep(x):   #生成器+函数(函数中有yield语句即为生成器函数)

    for i in range(3):   #有循环

        print('sleep {}'.format(i))

        yield from asyncio.sleep(x)   #asyncio.sleep(x),另一个生成器对象

 

loop = asyncio.get_event_loop()

loop.run_until_complete(sleep(10))   #sleep(3)必须要有括号,sleep为生成器函数,可理解为拿到生成器对象,用返回的对象循环

loop.close()

 

例:

async def sleep(x):   #3.5ver用法

    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(x)

 

loop = asyncio.get_event_loop()

tasks = [sleep(3), showthread(3)]   #放协程对象

loop.run_until_complete(asyncio.wait(tasks))

loop.close()

 

print(asyncio.iscoroutinefunction(sleep))

print(asyncio.iscoroutine(showthread))

输出:

[<_MainThread(MainThread, started 19172)>]

sleep 0

[<_MainThread(MainThread, started 19172)>]

sleep 1

[<_MainThread(MainThread, started 19172)>]

sleep 2

True

False

 

例:

TcpEchoServer

 

 

aiohttp

>pip install aiohttp

 

对于socket,在accept()后,关键是recv()send()

对于http,关键是requestresponse

 

异步的好处:

没有多线程,并发用多进程;

多进程 + 协程,可完成很高的并发;

 

简单函数-->多线程-->IO复用-->异步io

 

例,服务端:

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(status=200,text=request.match_info.get('id', '0000'))

 

app = web.Application()

app.router.add_get('/', indexhandle)

app.router.add_get('/{id}', handle)

web.run_app(app, host='0.0.0.0', port=9999)

输出:

======== Running on http://0.0.0.0:9999 ========

(Press CTRL+C to quit)

<MatchInfo {'id': '555'}: <ResourceRoute [GET] <DynamicResource  /{id}> -> <function handle at 0x00000000039989D8>>

 

 

例,客户端:

from aiohttp import ClientSession

import asyncio

 

async def get_html(url: str):

    async with ClientSession() as session:   #clientserver建立会话

        async with session.get(url) as res:   #response

            print(res.status)

            print(await res.text())

 

url = 'http://127.0.0.1:9999/555'   #服务端

 

loop = asyncio.get_event_loop()

loop.run_until_complete(get_html(url))   #爬虫的第一步,拿到html页面数据后,用第三方库解析html变成dom树,拿到想要的东西

loop.close()

输出:

200

555

 


向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI