记录一个python单线程、多线程简单爬虫的执行效率

python多线程与其他语言相比有很大的区别,python中的多线程,由于cil锁的缘故,导致cpu同一时间只能执行一个线程,这样产生的问题就是别管你的cpu是几核的,都没什么卵用。但是这种情况是计算密集性才会有的问题,如果牵涉到的是计算密集性,那么python可以通过多线程来做这种操作,这样就解决了多核缺并不能提高效率的问题。

今天要用的爬虫其实是cpu把任务分配给了其他硬件进行操作,cpu只牵涉到了分配,其他不用自己处理,这样即使是多线程,轮询分配下任务并不降低什么效率,同样类型的IO操作,我们都可以使用多线程。

import requests
from bs4 import BeautifulSoup
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
import time
all_urls = []
def get_url_list(target_url):
    list_infos = []
    # 访问目标地址
    ret = requests.get(url=target_url)
    soup = BeautifulSoup(ret.text, 'html.parser')
    list_box = soup.find('div', attrs={
        'class':'list'
    })
    lis = list_box.find_all('li')
    for li in lis:
        info = li.find('h3')
        title = info.find('a').text
        target = info.find('a').get('href')
        list_infos.append({
            'title' : title,
            'target' : target
        })
    return list_infos
def run():

    for item in range(1, 51):
        all_urls.append(get_url_list('http://www.chinamedevice.cn/product/12/11/1127/%s.html'%item))
# 进程执行的任务返回的结果保存至url列表
def get_result(future):
    all_urls.append(future.result())
def thred_run():
    # 创建一个包含5条线程的线程池
    with ThreadPoolExecutor(5) as pool:
        for item in range(1, 51):
            # 向线程池提交一个task, url会作为get_url_list()函数的参数
            res = pool.submit(get_url_list, 'http://www.chinamedevice.cn/product/12/11/1127/%s.html' % item)
            # 为res添加线程完成的回调函数
            res.add_done_callback(get_result)

if __name__ == '__main__':
    start = time.perf_counter()
    thred_run()
    # run()
    end = time.perf_counter()
    print(all_urls, len(all_urls), '总用时:%s' % (end - start))

单次测试,使用常规的单进程单线程爬取50页即1500条数据所耗费的时间大约在45秒左右;而我们使用单进程5线程获取同样的数据大概耗费了10秒左右,具体线程数根据自己需求