• python 协程


    多线程和多进程:
    优点:可以为阻塞操作提供异步执行
    缺点:无法无限制的创建线程

    进程池和线程池:
    好处:可以系统对进程和线程的创建和销毁的频率,从而降低系统的开销
    缺点:线程池和进程池是固定的。有上限。


    线程池的基本使用
    # 导入进程池的pool
    from multiprocessing.dummy import Pool
    # 实例化线程对象
    pool = Pool(4)
    # map func iterator chunksize
    pool.map(get_page,name_list)


    协程:
    单线程+异步协程(推介)
    evelent_loop: 事件循环,相当于一个无限循环,可以把一些函数注册到这个循环中

    coroutine:协程对象,我们可以把协程对象注册到事件循环中

    task:任务,他是对协程对象的进一步封装,包含了任务的每个状态

    future;代表将来执行或还没有执行的任务,task和future没有本质区别

    async: 定义一个协程
    await:挂起阻塞方法的执行



    import asyncio
    # 提供了async await 两个关键字

    async def requests1(url):
    print('正在请求的url',url)

    print('请求成功',url)
    # async 修饰的函数,调用之后返回的是一个协程对象
    c = requests1('http://www.baidu.com')

    print(c)


    # 创建一个事件循环对象
    loop = asyncio.get_event_loop()

    # 将协程对象注册到loop中,然后启动loop c 是协程对象

    loop.run_until_complete(c)





    # task 的使用

    loop = asyncio.get_event_loop()
    task = loop.create_task(c) # 将协程对象 传入loop ,loop创建一个task对象

    print(task) # 打印任务对象,正在执行,协程状态

    # 将任务对象注册到loop

    loop.run_until_complete(task)
    print(task) # 打印任务对象,表示任务已经完成




    # future

    loop = asyncio.get_event_loop()

    # 创建future对象

    task = asyncio.ensure_future(c) # 任务对象
    print(task)
    loop.run_until_complete(task) # 注册

    print(task)





    绑定回调函数



    import asyncio
    # 提供了async await 两个关键字

    async def requests1(url):
    print('正在请求的url',url)

    print('请求成功',url)
    return url
    # async 修饰的函数,调用之后返回的是一个协程对象
    c = requests1('http://www.baidu.com')

    print(c)



    # 绑定回调

    def callback_func(task):
    print(task.result()) # task.result() 返回任务对象的返回值

    loop = asyncio.get_event_loop()
    task = asyncio.ensure_future(c)
    # 当任务对象执行成功之后,执行回调函数 , 将回调函数绑定到任务对象
    task.add_done_callback(callback_func) # 默认将任务对象作为参数传递给回调函数
    loop.run_until_complete(task)


    多任务异步协程实现


    import asyncio
    import time

    async def request(url):
    print('正在下载:',url)
    time.sleep(3)
    print("下载完成",url)


    urls = [
    'https://www.baidu.com',
    'https://www.sougou.com',
    'https://www.xinlang.com',
    ]
    start = time.time()
    # 任务列表,需要粗放多个任务对象
    tasks = []
    for url in urls:
    c = request(url) # 协程对象
    task = asyncio.ensure_future(c) # 任务对象
    tasks.append(task)

    loop = asyncio.get_event_loop() # 事件循环
    loop.run_until_complete(asyncio.wait(tasks)) # 注册

    print(time.time()-start) # 9秒, 没有节省时间

    原因出在哪里?
    time.sleep(3)
    在异步协程中,如果出现同步模块相关的代码,那么就无法实现异步。
    解决
    asyncio.sleep(3)

    当在asyncio中遇到阻塞操作必须进行手动挂起
    await



    import asyncio
    import time

    async def request(url):
    print('正在下载:',url)
    # time.sleep(3)
    await asyncio.sleep(3)
    print("下载完成",url)


    urls = [
    'https://www.baidu.com',
    'https://www.sougou.com',
    'https://www.xinlang.com',
    ]
    start = time.time()
    # 任务列表,需要粗放多个任务对象
    tasks = []
    for url in urls:
    c = request(url) # 协程对象
    task = asyncio.ensure_future(c) # 任务对象
    tasks.append(task)

    loop = asyncio.get_event_loop() # 事件循环
    loop.run_until_complete(asyncio.wait(tasks)) # 注册

    print(time.time()-start) # 3.003420114517212秒,


    aiohttp+多任务异步协程


    import asyncio
    import aiohttp
    import requests
    import time


    urls = [
    'https://www.baidu.com',
    'https://www.sougou.com',
    'https://www.bilibili.com/',
    'https://www.bilibili.com/',
    'https://www.bilibili.com/',
    'https://www.bilibili.com/',
    'https://www.bilibili.com/',
    'https://www.bilibili.com/',
    'https://www.bilibili.com/',
    ]

    async def get_page(url):
    print("正在下载", url)
    res = requests.get(url) # 基于同步代码 , 必须使用基于异步的网络请求模块
    print(res.status_code)


    print("下载外币",url)
    start = time.time()

    tasks = []

    for url in urls:
    c = get_page(url)
    task = asyncio.ensure_future(c)
    tasks.append(task)


    loop = asyncio.get_event_loop()
    loop.run_until_complete(asyncio.wait(tasks))

    print(time.time()-start) #2.431379795074463



    aiohttp:
    pip install aiohttp
    使用该模块的clientsesession





    import asyncio
    import aiohttp
    import requests
    import time


    urls = [
    'https://www.baidu.com',
    'https://www.sougou.com',
    'https://www.bilibili.com/',
    'https://www.bilibili.com/',
    'https://www.bilibili.com/',
    'https://www.bilibili.com/',
    'https://www.bilibili.com/',
    'https://www.bilibili.com/',
    'https://www.bilibili.com/',
    ]

    async def get_page(url):
    print("正在下载", url)
    # res = requests.get(url) # 基于同步代码 , 必须使用基于异步的网络请求模块
    # print(res.status_code)
    async with aiohttp.ClientSession() as session:
    async with await session.get(url) as res :
    # text() 返回字符串数据
    # read() 返回二进制数据
    # json() 返回json对象
    # 注意获取响应数据之前,一定要使用await手动挂起
    page_text = await res.text(encoding='utf8')

    print(page_text)

    print("下载外币",url)
    start = time.time()

    tasks = []

    for url in urls:
    c = get_page(url)
    task = asyncio.ensure_future(c)
    tasks.append(task)


    loop = asyncio.get_event_loop()
    loop.run_until_complete(asyncio.wait(tasks))

    print(time.time()-start) # 1.3533799648284912

    # RuntimeWarning: coroutine 'ClientResponse.text' was never awaited
    # self._context.run(self._callback, *self._args)

    # 注意获取响应数据之前,一定要使用await手动挂起
    aiohttp
    get ,post

    ua伪装
    get
    headers paramas

    post
    headers data , proxy 代理ip不是字典,而是字符串http://ip:port



    协程:
    实现方式:
    1:greenlet 早期模块
    2:yield关键字
    3:asyncio装饰器 p3.4
    4:async await p3.5


    greenlet 实现协程


    from greenlet import greenlet




    def func1():
    print(1)
    gr2.switch()
    print(2)
    gr2.switch()


    def func2():
    print(3)
    gr1.switch()
    print(4)



    gr1 = greenlet(func1)
    gr2 = greenlet(func2)

    gr1.switch() # 第一步,执行func1

    # 1
    # 3
    # 2
    # 4



    yield 实现协程


    # yield



    def func1():
    yield 1
    yield from func2()
    yield 2


    def func2():
    yield 3
    yield 4



    f1 = func1()

    for item in f1:
    print(item)
    # 1
    # 3
    # 4
    # 2




    asyncio 遇到io操作自动切换
    coroutine过期了

    import asyncio


    @asyncio.coroutine
    def func1():
    print(1)
    yield from asyncio.sleep(1)
    print(2)


    @asyncio.coroutine
    def func2():
    print(3)
    yield from asyncio.sleep(2)
    print(4)


    tasks = [
    asyncio.ensure_future(func1()),
    asyncio.ensure_future(func2()),
    ]

    loop = asyncio.get_event_loop()
    loop.run_until_complete(asyncio.wait(tasks))



    import asyncio


    async def func1():
    print(1)
    await asyncio.sleep(1)
    print(2)



    async def func2():
    print(3)
    await asyncio.sleep(2)
    print(4)


    tasks = [
    asyncio.ensure_future(func1()),
    asyncio.ensure_future(func2()),
    ]

    loop = asyncio.get_event_loop()
    loop.run_until_complete(asyncio.wait(tasks))



    协程意义:

    在一个线程中如果遇到io等待的时间,线程不会傻傻等,利用空闲的时间再去干点其他事。

    事件循环:理解为一个死循环,去检测

    伪代码
    任务列表

    whle true :
    可执行的任务列表,已完成的任务列表=去任务列表检查所有的任务,将可执行和已完成任务返回

    for 就绪任务 in 可执行的任务列表
    执行已就绪的任务
    for 已完成的任务 in 已完成的任务列表
    任务列表中移除 已完成的任务

    如果任务列表中的任务已完成 终止循环


    import asyncio

    生成一个事件循环
    loop = asyncio.get
    将事件放到事件循环
    loop.run


    快速上手

    协程函数:定义函数的时候async def
    协程对象,执行协程函数的得到的协程对象

    协程函数
    async def func():
    pass

    result = func() 得到协程对象


    await

    可等待对象:
    协程对象, future , task 对象====》目前裂解成io等待

    import asyncio

    async def func():
    res = await asyncio.sleep(1)

    return res

    async.run(func())



    import asyncio

    async def others():
    print('start')
    await asyncio.sleep(2)
    print('end')
    return '返回值'


    async def func():
    print('111')


    res = await others()
    print('2222',res)


    res = await others()
    print('333',res)

    asyncio.run(func())

    一个协程函数可以有多个await


    task对象:
    干什么?

    在事件循环中并发添加多个任务。

    asyncio.create_task()方式创建多个task任务。
    这样可以将协程加入事件循环中
    还可以:
    loop.create_task() before p37
    looop.enture_future()

    asyncio.create_task() --python3.7 引入的



    async def others():
    print('start')
    await asyncio.sleep(2)
    print('end')
    return '返回值'


    async def func():
    print('111')

    # 创建任务,将协程对象添加到事件循环中
    task1 = asyncio.create_task(others())
    task2 = asyncio.create_task(others())


    print('任务创建成功')
    # 当执行某协程遇到io操作时,会自动切换执行其他任务
    # await是等待相对应的协程全部执行完毕再获取结果
    ret1 = await task1
    ret2 = await task2

    print(ret1,ret2)



    asyncio.run(func())

    # 111
    # 任务创建成功
    # start
    # start
    # end
    # end
    # 返回值 返回值




    async def others():
    print('start')
    await asyncio.sleep(2)
    print('end')
    return '返回值'



    task_list = [
    others(),
    others()
    ]

    done ,pending = asyncio.run(
    asyncio.wait(
    task_list
    )
    )

    future对象:

    更底层:
    task类的基类

    task继承future对象,task内部await结果的处理基于future对象
    理解为await等待处理


    async def main():
    loop = asyncio.get_running_loop()

    fut = loop.create_future()

    await fut

    asyncio.run(main())






    async def func(fut):
    print(1)
    await asyncio.sleep(2)
    fut.set_result('555')




    async def main():
    loop = asyncio.get_running_loop()

    fut = loop.create_future()

    await loop.create_task(func(fut))


    data = await fut
    print(data)

    asyncio.run(main())

    # 1
    # 555
    # sys:1: RuntimeWarning: coroutine 'others' was never awaited


    concurrent.futures.Future对象

    使用线程池和进程池实现异步操作




    from concurrent.futures import Future
    from concurrent.futures.thread import ThreadPoolExecutor
    from concurrent.futures.process import ProcessPoolExecutor

    import time

    def func(value):
    time.sleep(2)
    # print(value)
    return value
    pool = ThreadPoolExecutor(max_workers=5)


    for i in range(10):
    fut = pool.submit(func,i)
    print(fut)


    协程和进程池交叉使用

    比如
    mysql不支持asyncio
    有的第三方模块不支持协程


    import time
    import asyncio
    import concurrent.futures


    def func1():
    time.sleep(1)
    return 'sa'



    async def main():
    loop = asyncio.get_running_loop()
    # 在普通函数转为future对象
    fut = loop.run_in_executor(None,func1)

    print(fut)
    res = await fut

    print('res',res)


    asyncio.run(main())


    <Future pending cb=[_chain_future.<locals>._call_check_cancel() at /Users/lizejun/.pyenv/versions/3.8.0/lib/python3.8/asyncio/futures.py:357]>
    res sa
    什么时候使用
    在编程异步的时候,如果遇到第三方模块不支持异步。

    案例:asyncio+不支持异步的模块



    import asyncio
    import requests


    async def download(url):


    print('开始下载',url)

    loop = asyncio.get_running_loop()
    # request不支持异步,使用线程池配合实现异步
    future = loop.run_in_executor(None,requests.get,url)


    res = await future

    print('下载完成')
    import random
    filename = url.split('_')[-1]
    if len(filename) > 20:
    filename = str(random.randint(1,1000))+".jpg"

    with open(filename,mode='wb') as file_obj:
    file_obj.write(res.content)


    if __name__ == '__main__':

    url_list = [
    "https://ns-strategy.cdn.bcebos.com/ns-strategy/upload/fc_big_pic/part-00023-1899.jpg",
    "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1608623433169&di=2890da7609ad80683a8e642ae2f91a1c&imgtype=0&src=http%3A%2F%2F5b0988e595225.cdn.sohucs.com%2Fq_70%2Cc_zoom%2Cw_640%2Fimages%2F20180815%2Fc80db8ae0d044eafb020d6e91e6151f4.jpeg",
    "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1608623351187&di=ad5c0c3592dff8bdc0130634867b9a98&imgtype=0&src=http%3A%2F%2Fdingyue.ws.126.net%2FfMgAJpgFotLL5HnpJIGZvZukGgSwp1flGaDMD4yLT2Eps1552963002835.jpg",
    ]

    tasks = [download(url) for url in url_list]

    loop = asyncio.get_event_loop()
    loop.run_until_complete(asyncio.wait(tasks))



    异步迭代器:

    实现了__aiter__ __anext__()方法的对象,

    __aiter__ 必须返回一个awaitable对象

    async_for 会处理异步迭代器的__anext__方法返回的可等待对象,
    直到引发一个stopasynciteration异常

    异步迭代对象:
    可以在async_for语句中被使用的对象,,必须通过他的__aiter方法返回一个asyncthors_iterator


    import asyncio


    class Reader(object):

    '''自定义异步迭代器(同时也是异步可迭代对象)'''


    def __init__(self):
    self.count = 0


    async def readline(self):

    self.count += 1
    if self.count == 100:
    return None
    return self.count

    def __aiter__(self):
    return self

    async def __anext__(self):
    val = await self.readline()
    if val == None:
    raise StopAsyncIteration
    return val
    #
    # obj = Reader()
    # async for item in obj:
    # print(item)
    #
    # async for item in obj:
    # ^
    # SyntaxError: 'async for' outside async function


    # async for 必须写在协程函数内
    async def func():



    asyncio 异步上下文管理器

    这种对象通过定义aenter和aexit 方法对async with 语句中的环境进行控制



    import asyncio

    class AsyncCOntextManager:

    def __init__(self):
    self.conn = ''


    async def do_sometiong(self):
    pass

    async def __aenter__(self):

    pass

    async def __aexit__(self, exc_type, exc_val, exc_tb):
    pass

    async def func():
    async with AsyncCOntextManager() as f:
    res = await f.do_sometiong()
    print(res)

    if __name__ == '__main__':
    asyncio.run(func())



    菜鸟的自白
  • 相关阅读:
    Lua多条件排序
    python_request 使用jsonpath取值结果,进行接口关联
    python_xlutils : python利用xlutils修改表格内容
    python_reques接口测试框架,Excel作为案例数据源
    正则表达式re模块的基础及简单应用
    linux下Rtree的安装
    du和df不一致的解决方法
    windows 版Tomcat 7.0的配置
    linux下搭建svn服务器
    【leetcode】1. Two Sums
  • 原文地址:https://www.cnblogs.com/lzjloveit/p/14162322.html
Copyright © 2020-2023  润新知