美文网首页Python
Python高手进阶|实战4大并发秘籍

Python高手进阶|实战4大并发秘籍

作者: 菜鸟学python | 来源:发表于2021-01-05 22:11 被阅读0次

    天下武功唯快不破,在日常工作中,我们的很多task都会用到并发,毕竟大部分时候我们处理的工作都是大量的,如果慢慢的循环处理估计等的胡子都白了,所以学会Python里的并发很重要。Python有常见的4大并发大法,今天就带大家一起来学习一下。

    要点:

    • 手动线程池
    • concurrent.futures线程池
    • concurrent.futures进程池
    • gevent协程

      \normalsize\mathbf{01.} \normalsize\mathbf{实战爬取维基百科例子}

    平时我们有很多任务,尤其是比较耗时的大量任务要处理,一定会用到并发处理。毕竟串行太慢了,下面我们去爬一个维基百科的网站:

    我们来爬取红框里面的导航文本部分,这是一个非常简单的爬虫(关于爬虫的文章前面写的太多太多了,大家可以翻历史文章)

    1).连接网页

    2).爬取网页

    • 函数设计的时候我们希望入参是一个元组(url,words),方便后面做并发处理
    • 网页非常简单,直接用requests取爬取,获取text
    • 用pyquery来解析网页,获取对国家的描述
    • 数据结构用字典对来存储

      \normalsize\mathbf{02.} \normalsize\mathbf{PK前做点准备工作}

    1).如果我们现在要爬取100个国家的信息,有几种办法呢:

    • 最慢的串行爬取
    • 自己手动构建一个线程池,把要爬取的100国家都扔到共享队列里面,让多个线程共享爬取
    • 利用concurrent.futures标准库里的线程池来爬去
    • 用多进程来爬取,虽然网页请求是CPU密集型的,用进程有点浪费,但是我们作为对比,是可以试一下的
    • 用协程也叫微线程,是一种绿色线程,用来做高并发很爽

    2).为了准确的计算每一种方法的耗时,我们写一个函数专门来计算时间:

    下面我们用上面的5种方法逐一运行,为了简单期间我们统一爬取5个国家,每种方法上面用装饰器@cost_time来计算一下,看看到底哪种方便比较简单,速度又最快~~

    \normalsize\mathbf{03.} \normalsize\mathbf{慢慢的串行处理}

    先来段最通俗的one by one的串行处理

    爬取5个国家的简介花了17秒,串行因为在等待服务器的相应的时候傻等,所以浪费了很多时间

    \normalsize\mathbf{04.} \normalsize\mathbf{手动建多线程共享队列}

    利用queue有锁的功能,手动把数据塞进队列,然后多个线程共享爬取

    多线程确实非常快,只需要5秒左右就搞定了,但是用这种方法代码太多,有没有更优美的方法呢

    \normalsize\mathbf{05.} \normalsize\mathbf{用标准库里面的线程池}

    与其动手造轮子,不如用无所不能的库,Python里面的库真的太多太多了!这也是Python为啥这么火爆的原因之一.

    发现用系统的线程池跟手动的几乎差不多,但是大家发现没有用轮子来处理,代码量非常小,而且很优美!(这是Python之美,能用轮子尽量用轮子,简洁高效).

    有同学会问,有没有什么情况是一定要手动构建线程池,而不能用ThreadPoolExecutor,确实有这样的情况,大家思考一下,不明白的留言给我,偷偷告诉你.

    \normalsize\mathbf{06.} \normalsize\mathbf{用标准库的里进程池}

    既然上面有线程池,一定有进程池吧。是的,我们下面来看看杀鸡用牛刀的多进程处理,需要几秒呢:

    差不多也是5-6秒左右,多进程还是比较快的!但是我们这里是5个国家,如果500个你不可能开100个进程来处理呢,如果碰到非常巨大的并发量,又要节省系统资源,又要速度很快,怎么办呢,我们看最后一招

    \normalsize\mathbf{07.} \normalsize\mathbf{绝招,用协程来并发}

    用一下gevent这个库,功能强大使用简单,对协程的封装比较好。每当一个协程阻塞时,程序将自动调度,gevent帮我们处理了所有的底层细节

    gevent.spawn来创建一个一个的协程对象,然后joinall会等待所有的协程运行完成,最后我们就获取到几个国家的简介数据。

    哇协程果然很牛逼,只需要2.8秒左右,非常舒爽的感觉!但是这里因为requests库有个缺点,访问的时候是上一个访问结束,才能进行下一次访问!所以需要用gevent的猴子补丁.另外gevent虽然很好,但是它是大规模并发,如果发起10000个网络请求,估计很快会被封IP!

    好我们来总结一下:

    同步处理:17秒
    异步手动建线程池:5.5秒
    异步标准库线程池:5.2秒
    异步标准库进程池:5.9秒
    并发协程:2.8秒


    很明显用Gevent最快,尤其是在大规模的几十万级别的并发处理效果非常明显.

    线程池也是一个不错的选择,而且比较灵活,如果需要多个并发任务之间有交互的话,还是需要用线程池.

    那进程池呢,我们上面考虑的都是IO 密集型task,如果我们碰到了CPO型的那就必须要多核多CPU运行才能加速。毕竟Python有一个烦人的GIL。

    今天留一个讨论题:有多少人知道 并发和并行的区别,欢迎留言区讨论!


    最后推荐一下我们菜鸟学Python在B站的学习资料,菜鸟学Python在B站的官方名字为 “菜鸟玩Python”。目前已经录制了6个视频,累计有1.2万阅读。

    • 用Python做一个弹球游戏
    • 10行Python代码实现美图秀秀
    • 用Python做一个元宵节灯谜
    • 我用Python集齐五福
    • 50行代码,用Python批量做海量小姐姐的素描图
    • 用Python做一个缩放自如的圣诞老人

    目前wx搜索Python 【菜鸟学Python】排第二,汇聚了30万Python爱好者,累计原创近400篇趣味干货(爬虫,数据分析,算法,面试指南,原创趣味实战,Python游戏,机器学习),欢迎一起学Python,交流指正。

    相关文章

      网友评论

        本文标题:Python高手进阶|实战4大并发秘籍

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