单线程不足之处

当对多个url发送请求时,只有请求完第一个url才会接着请求第二个url(requests是一个阻塞的操作),比如下载图片,这种一个个执行的方式称为单线程。其存在等待的时间,这样效率是很低的。那我们能不能在发送请求等待的时候,为其单独开启进程或者线程以异步的方式进行,继续请求下一个url,执行并行请求呢?这样看起来相当于同时下载很多张图片一样,速度明显提升。

异步爬虫

有如下基于异步爬虫的方案

  • 多线程或多进程(不建议)

好处:可以为相关阻塞的操作单独开启线程或者进程,阻塞操作就可以异步会执行

弊端:不能无限制开启多线程或者多进程(需要频繁的创建或者销毁进程,线程)

  • 线程池或进程池(适当使用)

好处:可以降低系统对进程或线程创建和销毁的频率,从而很好的而降低系统的开销

弊端:线程或进程池中的数量是有上限的

  • 单线程+异步协程(推荐)

线程池

我们先来看看,使用常规的单线程方式下载东西

import time
def get_page(str):
    print("开始下载:",str)
    time.sleep(2)           #代表下载耗时两秒
    print("下载成功:",str)
    print('-------------------')

name_list = ['aa','bb','cc','dd']
for i in range(len(name_list)):
    get_page(name_list[i])

如下,全部下载完四个东西需要8.2秒。因为想下载下一个得等前一个下载完才行

python线程池中再起线程会有影响吗 python线程池并发爬虫_python线程池中再起线程会有影响吗

 使用线程池如下

# 1.倒入线程池模块对应的类
from multiprocessing.dummy import Pool
import time
def get_page(str):
    print("开始下载:",str)
    time.sleep(2)
    print("下载成功:",str)
    print('-------------------')

name_list = ['aa','bb','cc','dd']

# 2.实例化一个线程池对象,线程池中开辟四个线程对象,并行4个线程处理四个阻塞操作
pool = Pool(4) 
# 3.将列表中的每一个列表元素(可迭代对象)传递给get_page函数(发生阻塞的操作)进行处理
#map方法会有一个返回值为函数的返回值(一个列表),但是这里没有返回值所以不考虑
#调用map方法
pool.map(get_page,name_list)    #第一个参数为会发生阻塞的函数,第二个参数相当于形参
#map方法结束后关闭池子
pool.close()
#主线程等待子线程结束后再结束
pool.join()

此时耗时2.2秒

python线程池中再起线程会有影响吗 python线程池并发爬虫_线程池_02