zoukankan      html  css  js  c++  java
  • 线程池,协程,多任务异步

    基于flask的server断服务器

    from flask import Flask, render_template
    from time import sleep
    
    app = Flask(__name__)
    
    
    @app.route('/index')
    def index():
        sleep(2)
        return render_template('test.html')
    
    @app.route('/home')
    def index1():
        sleep(2)
        return render_template('test.html')
    
    @app.route('/login')
    def index2():
        sleep(2)
        return render_template('test.html')
    
    if __name__ == '__main__':
        app.run(threaded=True)   # 旧版本需要加上这个才能开启多线程
    
    

    线程池

    from multiprocessing.dummy import Pool
    import requests
    import time
    from lxml import etree
    
    start = time.time()
    urls = [
        'http://127.0.0.1:5000/index',
        'http://127.0.0.1:5000/home',
        'http://127.0.0.1:5000/login',
    ]
    pool = Pool(3) # 开启3个线程
    
    
    # 回调函数会异步处理列表中的每一个列表元素
    def get_request(url):
        page_text = requests.get(url).text
        return page_text
    
    
    page_text_list = pool.map(get_request, urls)
    
    
    # 异步解析数据
    def parse_text(page_text):
        tree = etree.HTML(page_text)
        tree.xpath('//*[@id="feng"]')
    
    
    pool.map(parse_text, page_text_list)
    
    print('总耗时', time.time()-start)
    

    协程的基本操作

    import asyncio
    import time
    
    async def get_request(url):
        print('正在请求', url)
        time.sleep(2)
        print('请求结束', url)
        return 'go go go go'
    
    # 创建一个协程对象
    c = get_request('www.1.com')
    # 创建一个任务对象
    task = asyncio.ensure_future(c)
    # 创建一个事件循环对象
    loop = asyncio.get_event_loop()
    # 将任务对象装载到事件循环对象这个容器中且启动事件循环
    loop.run_until_complete(task)
    

    任务对象的回调函数

    
    import asyncio
    import requests
    import time
    
    async def get_request(url):
        print('正在请求', url)
        time.sleep(2)
        print('请求结束', url)
        return 'go go go go'
    
    def parse(task):
        # result()返回的就是任务对象表示的特殊函数内部的返回值
        result = task.result()
        print(result)
    
    c = get_request('www.1.com')
    task = asyncio.ensure_future(c)
    # 给任务对象绑定一个回调 目的是为了函数return获取返回值
    # 该回调函数必须要有一个参数,这个参数表示的就是add_done_callback的调用者
    # 回调函数一定是在任务对象完全执行结束后才会被调用执行
    task.add_done_callback(parse)
    loop = asyncio.get_event_loop()
    loop.run_until_complete(task)
    
    

    多任务协程

    import asyncio
    import requests
    import time
    start = time.time()
    async def get_request(url):
        print('正在请求', url)
        # time.sleep(2)
        await asyncio.sleep(2)
        print('请求结束', url)
        return 'go go go go'
    
    urls = [
        'http://127.0.0.1:5000/index',
        'http://127.0.0.1:5000/home',
        'http://127.0.0.1:5000/login',
    ]
    tasks = []
    for url in urls:
        c = get_request(url)
        task = asyncio.ensure_future(c)
        tasks.append(task)
    loop = asyncio.get_event_loop()
    loop.run_until_complete(asyncio.wait(tasks)) # wait挂起
    print('总耗时', time.time()-start)
    # 上面代码出现的问题:
        # 1.多任务的模式并没有实现真正的异步
        # 2.wait()方法的作用
    
    

    多任务的异步爬虫

    import requests
    import time
    import asyncio
    import aiohttp
    from lxml import etree
    
    start = time.time()
    
    urls = [
        'http://127.0.0.1:5000/index',
        'http://127.0.0.1:5000/home',
        'http://127.0.0.1:5000/login',
    ]
    
    # async def get_request(url):
    #     # requests是一个不支持异步的模块
    #     page_text = await requests.get(url)
    #     return page_text
    
    async def get_request(url):
        async with aiohttp.ClientSession() as sess: #实例化了一个请求对象
            async with await sess.get(url) as response:  #get/post和requests的get/post用法几乎一致
                page_text = await response.text() #byte类型的数据使用read()
            return page_text
    
    def parse(task):
        page_text = task.result()
        tree = etree.HTML(page_text)
        tree.xpath('//a[@id="feng"]')
    
    tasks = []
    for url in urls:
        c = get_request(url)
        task = asyncio.ensure_future(c)
        task.add_done_callback(parse)
        tasks.append(task)
    
    loop = asyncio.get_event_loop()
    loop.run_until_complete(asyncio.wait(tasks))
    
    print('总耗时', time.time()-start)
    
    

    笔记

    异步爬虫的实现方式
        - 线程池
        - 多任务的异步协程
        - 多线程(生产者消费者模型)
    
    协程asyncio
    - 特殊的函数
        - 如果一个函数的定义被async关键字装饰,则该函数就是一个特殊函数
        - 特殊之处:
            - 1.特殊函数调用后,函数内部的程序语句没有被立即执行
            - 2.特殊函数调用后会返回一个协程对象
    - 协程
        - 对象,可以调用特殊函数返回一个协程。
        - 协程 == 特殊的函数 == 一组指定形式的操作
        - 协程 == 一组指定形式的操作
    - 任务
        - 对象.  任务对象其实就是一个高级的协程对象
        - 任务对象 == 协程 == 一组指定形式的操作
        - 任务 == 一组指定形式的操作
        - 特殊的机制:
            - 绑定一个回调函数
    
    - 事件循环(核心)
        - 对象asyncio.get_event_loop()
        - 事件循环你可以暂且把它当做一个载体或者容器
        - 将协程或者任务对象装载在事件循环这个容器中
            - run_until_complete
        - 开启事件循环
    - async
    
    - wait()
        - 用来对tasks这个任务列表进行指定操作.
        - wait可以将tasks任务列表中每一个任务对象一次赋予可挂起的权限
        - 挂起:可以让当前被执行的任务对象交出cpu的使用权
        - 当任务列表被wait方法修饰处理后,依然没有出现异步的效果
            - 在特殊函数内部的实现语句中不可以出现不支持异步模块的代码,否则会中断异步效果
    
    - await
        - 是可以确保在异步的过程中,让阻塞操作可以执行完毕
    
    支持异步的网络请求模块
        - aiohttp
        - pip install aiohttp
        - 代码实现:
            - 第一步:编写基本架构
            async def get_request(url):
                with aiohttp.ClientSession() as sess: #实例化了一个请求对象
                    with sess.get(url) as response:  #get/post和requests的get/post用法几乎一致
                        page_text = response.text() #byte类型的数据使用read()
                    return page_text
            - 第二步:补充细节
                - 在每个with前加上async关键字
                - 在每一步阻塞前加上await关键字
                async def get_request(url):
                    async with aiohttp.ClientSession() as sess: #实例化了一个请求对象
                        async with await sess.get(url) as response:  #get/post和requests的get/post用法几乎一致
                            page_text = await response.text() #byte类型的数据使用read()
                        return page_text
    
    流程:
        首先确保任务列表可以被挂起,然后依次执行,当执行任务列表里面的A任务时,遇到await asyncio.sleep(2),遇到阻塞,
        将A任务对象挂起,交出CPU使用权,执行任务列表里面B任务对象获得使用权,遇到await asyncio.sleep(2),遇到阻塞,
        将B任务对象挂起,交出CPU使用权,执行任务列表里面C任务对象获得使用权,遇到await asyncio.sleep(2),遇到阻塞,
        将C任务对象挂起,交出CPU使用权,可能C还没执行完的时候,A任务对象开始从之前阻塞的地方往下执行。后面B.C同样
    
    

    -------------------------------------------

    个性签名:代码过万,键盘敲烂!!!

    如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢!

  • 相关阅读:
    vim cheat
    latex base
    latex font
    lstings
    使用React 如何设计 模板自定义的框架
    react hooks 的更进一步适应性使用
    IDEA反编译jar包源码
    Redis Lua实战
    Spring AOP拦截并打印controller层请求日志
    漏桶算法和令牌桶算法的区别
  • 原文地址:https://www.cnblogs.com/weiweivip666/p/14028177.html
Copyright © 2011-2022 走看看