异步程序有多种实现方法,分别为多线程、多进程、协程、进程池、线程池等等,从性能的角度来讲,倾向于用线程池或者协程,多进程会耗费大量的系统资源,加速效果并不明显,我们这篇文章主要讲一下线程池的使用。

案例的方向是多线程下载,使用的模块为multiprocessing.dummy。首先第一步收集我们要下载的文件,这里我们选择了四个文件,分别为QQ浏览器、搜狗浏览器、百度输入法和搜狗输入法的安装包,代码如下。

多线程版本
单线程版本
结果对比
下载的软件

从理论上来讲,线程池是要比单线程要快,但也不绝对,我这里简单地给大家讲解一下代码的原理。

首先,引入Pool对象,注意要区分大小写,from multiprocessing.dummy import Pool,这一步是比较简单的。第二,实例化一个pool对象,pool的参数为线程池的数量,例子中pool的参数为4,即线程池内的线程有4个。第三,向pool对象传参,第一个参数是需要让线程池执行的函数,第二个参数为url列表,本例中pool.map(download,url_list),download就是线程池需要执行的函数。第四,编写download函数,如果需要返回值的话就写返回值,pool.map的返回值是一个map对象,类似列表,可以迭代。本例中还有其他几个知识点大家可以参考学习下,比如提取url中的文件名,file=re.findall(".*\/(.*?)$",urlparse(url).path)[0],笔者使用了正则和urlparse模块想结合的方法,关于正则表达式,.*是贪婪匹配的意思,$是末尾的意思,括号代表分组优先显示。

线程池的写法还可以扩展,因为pool.map(download,url_list)中的第二个参数只要是可迭代对象就行,而map函数的返回值也是一个可迭代对象,理论上线程池可以链式使用。

后面笔者会写一篇关于协程的文章。

相关文章