多线程爬虫

python 爬虫 多进程 爬虫 多线程 多进程_python 爬虫 多进程

    建立爬虫是为了提高效率,而建立多线程正是提高效率的方法之一,单线程爬虫只有一个线程,在每次访问网页时,不能够充分利用网络带宽,从而造成资源的浪费。

    Python在设计的时候,有一个全局解释器(Global Interpreter Lock),导致Python的多线程都是伪线程,其本质还是一个单线程,只是这个线程每个事情只做几毫秒几毫秒以后就保存数据,换做其他的事,几毫秒之后再做其他的事,一轮之后又回到第一件事,恢复数据再做几秒,然后有重复刚才的动作。简单来说就是同时在做几件事。

多进程库:

    multiprocessing本身是Python的多进程库,用来处理与多进程相关的操作。由于进程与进程之间不能共享内存和堆栈空资源,而且启动新的进程开销也比其他线程大得多,因此使用多线程来爬取比使用多进程有更多的优势。multiprocessing下面有一个dummy模块,他可以是Python的线程使用multiprocessing的各种方法。
    dummy下面有一个Pool类,他用来实现多线程。这个线程池有一个Map()方法,可以让线程池里面的线程“同时”执行一个函数。

for i in range(10):
    print(i**i)

这种方式的运行效率或者说执行效率不高,而如果使用多线程技术,可以同时计算很多个数的平方。这时就需要使用multiprocessing来实现

from multiprocessing.dummy import Pool

    def Test(num):
        return num * num
    
    pool = Pool(3)
    oright1 = [x for x in range(10)]
    oright = pool.map(Test,oright1)
    print(f"计算0-9的平方和分别为: { oright }")

先初始化一个有3个线程的线程池,,这三个线程池负责计算10个数字的平方,注意是同时进行计算的。map方法接收了两个参数(Test,oright1),第一个是函数名(注意不能带括号),第二个参数是一个可迭代的对象,这个可迭代对象里面的每一个元素都会被函数Test调用接收来作为参数,因为没有使用IQ流操作,所以在Python GIL的影响下,使用三个线程并不会是代码的运行时间小于单线程的运行时间(运行时等了好一会才出来,我以为是空指针异常呢,尴尬)。

除了列表以外,元祖、集合、字典都可以作为map()的第二个参数。

实例:

import requests
import time
from multiprocessing.dummy import  Pool

def query(url):
    requests.get(url)
    return url

start = time.time()
for i in range(100):
    query("http://baidu.com")
end = time.time()
print(f"单线程循环访问百度100次:耗时{ end - start}")

start = time.time()
url_list = []
for i in range (100):
    url_list.append("http://baidu.com")
pool = Pool(5)
pool.map(query,url_list)
end = time.time()
print(f"5次线程访问百度首页:耗时:{ end - start}")

两者进行对比就可以看出来两者的区别。

单线程循环访问百度100次:耗时20.2206449508667
5次线程访问百度首页:耗时:3.9783244132995605

 

小沐CA