zoukankan      html  css  js  c++  java
  • Event事件,进程池与线程池,高性能爬取梨视频,协程,协程的目的,gevent。

    1.Event事件

    Event 事件的作用:

    用来控制线程的执行。

    由一些线程去控制另一些线程。

    from threading import Event
    
    调用Event 类实例化一个对象。 e = Event
    若该方法出现在任务中,则为False,阻塞  
    e.wait()  #False
    若该方法出现在任务中,则将其他线程的Flase改为True,进入就绪态与运行态
    e.set()  # True
    
    

    2.进程池与线程池

    1)什么是进程池与线程池?
    进程池与线程池是用来控制当前程序允许创建(进程/线程)的数量.
    2)进程池与线程池的作用:
    保证在硬件允许的范围内创建 (进程/线程) 的数量.

    3)如何使用:

    from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
    import time
    
    # ProcessPoolExecutor(5)  # 5代表只能开启5个进程
    # ProcessPoolExecutor()  # 默认以CPU的个数限制进程数
    
    pool = ThreadPoolExecutor(5)  # 5代表只能开启5个线程 -5 +1 -1 +1 -1
    # ThreadPoolExecutor()  # 默认以CPU个数 * 5 限制线程数
    
    # t = Tread()  # 异步提交
    # t.start(0)
    
    # pool.submit('传函数地址')  # 异步提交任务
    # def task():
    #     print('线程任务开始了...')
    #     time.sleep(1)
    #     print('线程任务结束了...')
    #
    #
    # for line in range(5):
    #     pool.submit(task)
    
    
    # 异步提交任务
    # pool.submit('传函数地址').add_done_callback('回调函数地址')
    def task():
        print('线程任务开始了...')
        time.sleep(1)
        print('线程任务结束了...')
        return 123
    
    # 回调函数
    def call_back(res):
        print(type(res))
        # 注意: 赋值操作不要与接收的res同名
        res2 = res.result()
        print(res2)
    
    for line in range(2):
        pool.submit(task).add_done_callback(call_back)
        
    #
    线程任务开始了...
    线程任务开始了...
    线程任务结束了...
    <class 'concurrent.futures._base.Future'>
    123
    线程任务结束了...
    <class 'concurrent.futures._base.Future'>
    123
    

    高性能爬取梨视频

    网站主页:
        https://www.pearvideo.com/
    
    requests: 用户封装底层socket套接字
        - 打开CMD
            # 下载第三方模块
            >> pip3 install requests
    
    https://www.pearvideo.com/video_1614813
    https://www.pearvideo.com/video_1615201
    
    1.从主页中获取所有的视频ID号(1615201,1614813...)
        - 拼接视频详情页url
        https://www.pearvideo.com/video_ + '视频ID号'
    
    2.在视频详情页中获取真实视频url
        srcUrl="()"
    
    3.往真实视频url地址发送请求获取 视频 二进制数据
    
    4.最后把视频二进制数据保存到本地
    
    ## pip3 install requests  #终端输入:pip3 install requests 
    from concurrent.futures import ThreadPoolExecutor
    import requests
    import re
    import uuid
    

    代码:

    from concurrent.futures import ThreadPoolExecutor
    import requests
    import re
    import uuid
    
    pool = ThreadPoolExecutor(200)
    
    # 1.发送请求函数
    def get_page(url):
        response = requests.get(url)
        return response
    
    # 2.解析主页获取视频ID号
    def parse_index(response):
        id_list = re.findall(
            '<a href="video_(.*?)".*?>',
            response.text,
            re.S
        )
        return id_list
    
    # 3.解析视频详情页获取真实 视频链接
    def parse_detail(res):
        response = res.result()
        movie_detail_url = re.findall('srcUrl="(.*?)"', response.text, re.S)[0]
        print(f'往视频链接: {movie_detail_url}发送请求...')
    
        # 异步往视频详情页链接发送请求,把结果交给
        pool.submit(get_page, movie_detail_url).add_done_callback(save_movie)
        return movie_detail_url
    
    # 4.往真实视频链接发送请求,获取数据并保存到本地
    def save_movie(res):
        movie_response = res.result()
        # print(1111)
        # movie_response = get_page(movie_detail_url)
        # print(movie_response)
        name = str(uuid.uuid4())
        print(f'{name}.mp4视频开始保存...')
        with open(f'{name}.mp4', 'wb') as f:
            f.write(movie_response.content)
        print('视频下载完毕!')
    
    if __name__ == '__main__':
    
        # 1.访问主页获取数据
        index_response = get_page('https://www.pearvideo.com/')
    
        # # 2.解析主页获取所有的视频id号
        id_list = parse_index(index_response)
        print(id_list)
        # 3.循环对每个视频详情页链接进行拼接
        for id in id_list:
            print(id)
            detail_url = 'https://www.pearvideo.com/video_' + id
    
            # 异步提交爬取视频详情页,把返回的数据,交给parse_detail(回调函数)
            pool.submit(get_page, detail_url).add_done_callback(parse_detail)
    

    3.协程

    进程:资源单位

    线程:执行单位。

    协程:在单线程下实现并发。

    注意:

    协程不是操作系统资源,他是程序取的名字,为让单线程能实现并发。

    协程的目的:

    ​ 操作系统:

    ​ 躲到技术,切换+保存状态

    ​ 1.遇到 IO

    ​ 2.CPU执行时间长

    协程意义:

    ​ 通过手动模拟操作系统‘多道技术’,实现 切换+保存。

    ​ 1.手动实现 遇到 IO却换,欺骗操作系统误以没有 IO操作。

    ​ 单线程 遇到 IO ,切换 + 保存状态。

    ​ 单线程 计算密集型。来回切换 + 保存状态,反而效果更低

    优点:

    在 IO密集型的情况下,会提高效率。

    缺点:

    若在计算密集型的情况下,来回切换,反而效率更低。

    如何实现协程:切换 + 保存状态。

    基于 yield 并发执行(验证计算密集型的情况下,反而效率更低)

    并发:切换

    # 串行执行(串行比协程并发性更高)
    import time
    def func1():
        for i in range(10000000):
            i+1
    def func2():
        for i in range(10000000):
            i+1
    
    start = time.time()
    func1()
    func2()
    stop = time.time()
    print(stop-start)   #1.0149040222167969
    
    
    # 验证计算密集型的情况下效果更低  #  1.2908563613891602   还比如串行
    # 基于yield并发执行
    import time
    def func1():
        while True:
            10000000+1
            yield
    def func2():
        # g 生成器对象
        g = func1()
        for i in range(10000000):
            # time.sleep(100)# 模拟 IO,yield 并不会捕捉到并自动切换。
            i+1
            next(g)   #每次执行next相当与切换到func1下面。
    
    start = time.time()
    func2()
    stop = time.time()
    print(stop-start)  # 1.2908563613891602
    
    # 两个都是计算密集型,但是通过手动实现 切换+保存执行效率会低一些(用的秒长一些)。
    
    

    gevent

    是一个第三方模块,可以帮你监听 IO操作,并切换。

    需要下载:pip3 install gevent

    使用gevent目的:

    为了实现单行线程下,实现遇到 IO, 保存状态 +切换

  • 相关阅读:
    查看windows下指定的端口是否开放
    网易云音乐评论爬虫:爬取歌曲的全部评论
    用 Python 玩转 GitHub 的贡献板
    用python实现linux口令破解
    Python 音频数据扩充的技巧
    教你使用python+Opencv完成人脸解锁
    opencv+Python特征检测及K-最近邻匹配
    opencv+python 统计及绘制直方图
    学会用这个工具做分析,1年积累3年工作经验
    15分钟,教你用Python爬网站数据,并用BI可视化分析!
  • 原文地址:https://www.cnblogs.com/WQ577098649/p/11735795.html
Copyright © 2011-2022 走看看