分享

Python并发·多线程基础·放开threading,拥抱futures

 庆亮trj21bcn0z 2017-12-15

昨天双十二,买了一波东西,所以停更了一天,哈哈。


上篇文章我们介绍了怎么抓取ajax内容,然而运行的时候会发现要爬取的链接比较多,简单的for循环速度太慢。

这就是今天要介绍的内容了。

不过,我今天不打算介绍threading,而是介绍更为简易的并发框架--concurrent。

由于concurrent基本使用实在太过简单,近乎弱智,先来说点别的。

CPython的GIL

作为Python程序员,GIL应该是基础知识,就当我再重复一遍吧。

CPython解释器本身不是线程安全的,因此存在全局解释器锁(GIL),1次只能使用1个线程执行Python字节码。因此,1个Python进程通常不能同时使用多个CPU核心。

换句话说,很多时候Python的多线程没有什么意义。

虽然这只是解释器的做法,不代表Python语言本身存在这个限制,比如Jython就不存在GIL,但由于CPython是官方实现,久而久之就形成了这样的认知。

不过,Python标准库中所有执行阻塞型I/O操作的函数,在等待操作系统返回结果时都会释放GIL,所以Python在这个场合可以使用多线程为程序加速:当1个Python线程等待网络响应时,阻塞型I/O函数会释放GIL,再运行1个线程

爬虫正是I/O密集型作业。

如何编写代码

threading模块的资料网上应该一大把了,而且比起今天要讲的模块来说还是有点复杂的,大多数时候我们不需要那么麻烦。

所以我今天不打算介绍这个模块,而是选择了concurrent模块。

Python并发·多线程基础·放开threading,拥抱futures

就以昨天最简单的代码为例好了,简单明了的代码有助于更快熟练基本使用,之后就可以自己动手写更复杂的代码了。

现在就来介绍concurrent的简单之处:只需要把for循环改动一下,就可以支持多线程了。

当然,首先需要导入:

from concurrent import futures

我们只需要把main()函数中的for循环拿出来改动一下:

Python并发·多线程基础·放开threading,拥抱futures

这就是基本的多线程了。

workers用来设置线程数,也就是futures.ThreadPoolExecutor()的参数,注意,线程数不是越大越好,太多线程的开销会很大。这里在最上面设置了MAX_WORKERS=20,也就是在min()函数与urls列表长度比较后的最大的线程数,可以自己设置其他大小。

核心代码其实就2行,下面这行使用了map()映射,传入列表,get_html是接受列表每个元素的函数名。

为返回值设置一个变量不是必须的,return len(list(r))只是方便异常在此抛出。

这样,就完成了一个Python版本多线程的代码,是不是相当简单呢?

如果看threading模块的使用比较困惑的话,先来试试这个模块吧,本身也是Python官方更推荐使用的模块~

那么,就自己动手试试吧!

今天就讲到这里,完整可运行的代码可以在https://github.com/lucays/toutiao/tree/master/9直接获取。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多