以爬虫为例,单线程,协程,线程,进程之间性能的比较,原来协程可以这么快?
生活随笔
收集整理的這篇文章主要介紹了
以爬虫为例,单线程,协程,线程,进程之间性能的比较,原来协程可以这么快?
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
前言
因為剛剛學習到了協程,然后之前也對爬蟲有一定的了解,所以打算結合之前學的線程和進程,和協程進行對比,看看它的性能到底有多高,在測試完成后,結果還是不錯的!下面就直接上代碼了,因為代碼邏輯都比較簡單,我就不一一解釋了,重點是看測試結果,真的很讓人興奮!!!
案例
我這里以爬取一個網站上的所有國家的旗幟為例。(下圖為爬取結果,共192張)分別利用了單線程,協程,多線程,多進程進行爬取測試。線程的效率真的已經很高了,但是協程居然比它還高!!!
定位旗幟的url
我這里使用的xpath對元素進行定位。
?
相關代碼:
# 獲取各國國旗的下載地址 def get_country_img_urls() -> List[Tuple]:url = 'http://www.51zzl.com/jiaoyu/guoqi.asp'response = get(url, headers=HEADERS)response.encoding = 'gb2312' # 編碼格式html = response.texte = etree.HTML(html)country_url_li, country_name_li = e.xpath('//ul[@class="gq"]/li/img/@src'), e.xpath('//ul[@class="gq"]/li/span/text()') # xpath獲取國家名稱和圖片地址country_name_url_li = []for country_url, country_name in zip(country_url_li, country_name_li):country_name_url_li.append((country_name, f'http://www.51zzl.com{country_url}'))return country_name_url_li?這個函數的主要功能就是,拿到所有旗幟的url,并同它的國家名以列表的形式返回。
下載圖片的函數
# 下載一張圖片 def download_one(name: str, url: str) -> Tuple:'''下載到圖片的二進制數據并返回'''response = get(url, headers=HEADERS)content = response.contentreturn (name, content)保存圖片的函數
# 保存一張圖片 def save_one(name: str, content: bytes) -> None:path_ = 'imgs'if not path.exists(path_): mkdir(path_)save_path = f'{path_}/{name}.gif'with open(save_path, 'wb') as f:f.write(content)# 進度條process_bar()下載并保存一張圖片
# 下載并保存一張圖片 def download_save_one(name, url):name, content = download_one(name, url)save_one(name, content)這個函數其實就是對上面兩個函數的調用。
單線程版
# 串行執行 @clokced def single_execute(country_name_url_li):while country_name_url_li:download_save_one(*country_name_url_li.pop())協程版
# 下載 并保存(協程版) async def async_spider(name, url):path_ = 'imgs'if not path.exists(path_): mkdir(path_)save_path = f'{path_}/{name}.gif'session = ClientSession()async with session.get(url) as img_data:async with aio_open(save_path, 'wb') as f:await f.write(await img_data.content.readany())await session.close() # 關閉會話# 進度條process_bar()多線程版
# 多線程執行 @clokced def mul_th_execute(country_name_url_li):th_pool = ThreadPoolExecutor(len(country_name_url_li))while country_name_url_li:th_pool.submit(download_save_one, *country_name_url_li.pop())th_pool.shutdown()多進程版
# 多進程執行 @clokced def mul_pr_execute(country_name_url_li):# 創建和cpu數量相同的進程數pr_pool = ProcessPoolExecutor(cpu_count())while country_name_url_li:pr_pool.submit(download_save_one, *country_name_url_li.pop())pr_pool.shutdown()值得注意的是,因為多各個進程之間是隔離的,所以這里使用了Manager實現進程之間的通信。
?測試結果
單線程測試結果
單線程爬取圖片
協程測試結果
多線程測試結果?
?多進程測試結果
?單線程:21s
多進程:19.24s
多線程:0.35s
協程:0.19s
多進程和單線程的速度差不多;多線程和協程的速度比它們快了將近100倍的量級,而協程的速度又差不多是多線程的兩倍!
?賞心悅目的測試結果!!!
同步更新于個人博客系統:以爬蟲為例,單線程,協程,線程,進程之間性能的比較,原來協程可以這么快?
?源碼:
# -*- coding: UTF-8 -*- '''*****************LLL********************** @Project :17.使用future處理并發 * @File :lll01_下載各國的國旗.py * @IDE :PyCharm * @Author :LLL * @Date :2022/5/1 16:05 ***************************************** ''' from asyncio import get_event_loop, wait from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor from multiprocessing import cpu_count, Manager from functools import wraps from sys import stdout from time import time from typing import List, Tuple from aiofiles import open as aio_open from aiohttp import ClientSession from requests import get from os import path, mkdir from lxml import etree# 請求頭 HEADERS = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.60 Safari/537.36', }# 計時裝飾器:用來計算一個函數執行所需花費的時間 def clokced(func):@wraps(func) # 將原函數的函數名等一些屬性一并“帶過來”def clock(*args, **kwargs):start = time()res = func(*args, **kwargs)end = time()print(f' {func.__name__}執行耗時:{end - start}.')return resreturn clock# 進度條 def process_bar():global country_name_url_li, original_sumnow_len = len(country_name_url_li)done = original_sum - now_lenstdout.write('\r{}{}%'.format('#' * int(done * 50 / original_sum), '%.2f' % (done * 100 / original_sum))) # \r:回到首行stdout.flush()# 獲取各國國旗的下載地址 def get_country_img_urls() -> List[Tuple]:url = 'http://www.51zzl.com/jiaoyu/guoqi.asp'response = get(url, headers=HEADERS)response.encoding = 'gb2312' # 編碼格式html = response.texte = etree.HTML(html)country_url_li, country_name_li = e.xpath('//ul[@class="gq"]/li/img/@src'), e.xpath('//ul[@class="gq"]/li/span/text()') # xpath獲取國家名稱和圖片地址country_name_url_li = []for country_url, country_name in zip(country_url_li, country_name_li):country_name_url_li.append((country_name, f'http://www.51zzl.com{country_url}'))return country_name_url_li# 下載一張圖片 def download_one(name: str, url: str) -> Tuple:'''下載到圖片的二進制數據并返回'''response = get(url, headers=HEADERS)content = response.contentreturn (name, content)# 保存一張圖片 def save_one(name: str, content: bytes) -> None:path_ = 'imgs'if not path.exists(path_): mkdir(path_)save_path = f'{path_}/{name}.gif'with open(save_path, 'wb') as f:f.write(content)# 進度條process_bar()# 下載并保存一張圖片 def download_save_one(name, url):name, content = download_one(name, url)save_one(name, content)# 串行執行 @clokced def single_execute(country_name_url_li):while country_name_url_li:download_save_one(*country_name_url_li.pop())# 下載 并保存(協程版) async def async_spider(name, url):path_ = 'imgs'if not path.exists(path_): mkdir(path_)save_path = f'{path_}/{name}.gif'session = ClientSession()async with session.get(url) as img_data:async with aio_open(save_path, 'wb') as f:await f.write(await img_data.content.readany())await session.close() # 關閉會話# 進度條process_bar()# 協程執行 @clokced def async_excute(country_name_url_li):loop = get_event_loop()tasks = []while country_name_url_li:tasks.append(loop.create_task(async_spider(*country_name_url_li.pop())))loop.run_until_complete(wait(tasks))loop.close()# 多線程執行 @clokced def mul_th_execute(country_name_url_li):th_pool = ThreadPoolExecutor(len(country_name_url_li))while country_name_url_li:th_pool.submit(download_save_one, *country_name_url_li.pop())th_pool.shutdown()# 多進程執行 @clokced def mul_pr_execute(country_name_url_li):# 創建和cpu數量相同的進程數pr_pool = ProcessPoolExecutor(cpu_count())while country_name_url_li:pr_pool.submit(download_save_one, *country_name_url_li.pop())pr_pool.shutdown()if __name__ == '__main__':# 使用Manager實現進程之間的通信with Manager() as manager:country_name_url_li = get_country_img_urls()original_sum = len(country_name_url_li) # 一開始的總數# 串行執行single_execute(country_name_url_li)# 協程執行# async_excute(country_name_url_li)# 多線程執行# mul_th_execute(country_name_url_li)# 多進程執行# mul_pr_execute(country_name_url_li)總結
以上是生活随笔為你收集整理的以爬虫为例,单线程,协程,线程,进程之间性能的比较,原来协程可以这么快?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 效率工具 001 | 手把手教你满速(不
- 下一篇: USB设备驱动学习记录