爬蟲多線程

關(guān)于臭名昭著的"GIL"嚴(yán)重阻礙了python多線程在實(shí)際工程上的應(yīng)用,很多人理直氣壯的說:“為什么要用python里面的多線程,它的速度比單線程還慢”。實(shí)際上,這句話對(duì)了一半,在計(jì)算密集型任務(wù)中,由于GIL的存在,即使你的電腦是多核超棒,但是任意一個(gè)時(shí)刻只能有一個(gè)線程在運(yùn)行,WTF!但是很多人就會(huì)問了,既然python的多線程這么菜,那么它存在的意義是什么呢?為了增強(qiáng)本文的實(shí)用性,我不會(huì)糾結(jié)原理,而是介紹一種優(yōu)雅的方法使用python里面的多線程。
我們會(huì)在主要做I/O操作的,最典型的就是網(wǎng)絡(luò)連接的時(shí)候去使用python里面的多進(jìn)程,我們可以創(chuàng)建幾百個(gè)這樣的線程,當(dāng)有的線程在請(qǐng)求網(wǎng)絡(luò)連接的時(shí)候,其他線程還可以繼續(xù)處理數(shù)據(jù)。當(dāng)然對(duì)于密集型計(jì)算,我還是會(huì)多選擇多線程并發(fā),這也不是我們這篇文章講述的內(nèi)容了。
說起并發(fā),多線程之類的,很多人總是拿出什么生產(chǎn)者和消費(fèi)者之類的問題,對(duì)此我想說,我完全不想知道這些,知道這些能有什么用呢,去參加操作系統(tǒng)考試嗎?我們要優(yōu)雅,不要污。
加入我們遇到了這樣的一個(gè)任務(wù),你有成百上千的url,你想把對(duì)應(yīng)的網(wǎng)頁(yè)下載下來(lái),我相信研究過爬蟲的同學(xué)肯定會(huì)遇到這個(gè)問題。我會(huì)說我曾經(jīng)爬下了豆瓣妹子里面所有妹子的性感照片嗎,需要的話可以聯(lián)系我。為了使問題簡(jiǎn)單化,我們假設(shè)這些url已經(jīng)被你知道了。

urls = [
    'http://baidu.com.com',
    'http://dataunion.org/21885.html',
    'http://blog.jobbole.com/98480/',
    'http://www.itdecent.cn/users/c5fde99df3f2/latest_articles',
]
urls = urls*100 #生成400個(gè)url

Example 1:使用傳統(tǒng)的單線程去下載這些網(wǎng)頁(yè)

import time
import requests

def download(url):
    try:
        return requests.get(url,timeout=0.7)   #timeout這個(gè)參數(shù)很有必要,加入你不慎去訪問google等我國(guó)禁止的網(wǎng)站,那么程序在嘗試0.7秒鐘連接不上的時(shí)候,那么會(huì)放棄
    except:
        pass
start = time.time()
responses = [download(url) for url in urls]
html = [response.text for response in responses if hasattr(response,"text")]
end = time.time()
print ("Time: %f seconds" % (end - start))
Time: 169.916672 seconds

我們提取了400個(gè)網(wǎng)頁(yè)里面的文字(其實(shí)只下載了將近300個(gè),有100個(gè)網(wǎng)頁(yè)被我們因?yàn)樵谥付〞r(shí)間內(nèi)連接不上,我們放棄了),在單線程的情況下,差不多花了170秒,但是我們的實(shí)際工程中,隨時(shí)可能面對(duì)的是幾十萬(wàn)個(gè)網(wǎng)頁(yè)信息的搜索,這個(gè)時(shí)間就很驚人了。

我們想要優(yōu)雅的使用python多線程,我們需要借助tomorrow這個(gè)庫(kù),只需要一句話,就可以讓你的代碼完成速度的蛻變!
Example 1:使用多線程去下載這些網(wǎng)頁(yè)

import time
import requests
from tomorrow import threads
@threads(100)                         #我們開一百個(gè)線程去搞定我們的下載任務(wù)
def download(url):
    try:
        return requests.get(url,timeout=0.7)   #timeout這個(gè)參數(shù)很有必要,加入你不慎去訪問google等我國(guó)禁止的網(wǎng)站,那么程序在嘗試0.7秒鐘連接不上的時(shí)候,那么會(huì)放棄
    except:
        pass
start = time.time()
responses = [download(url) for url in urls]
html = [response.text for response in responses if hasattr(response,"text")]
end = time.time()
print ("Time: %f seconds" % (end - start))
Time: 11.314254 seconds

對(duì)比結(jié)果簡(jiǎn)直震撼,后一個(gè)版本的代碼只是比前一個(gè)單線程的代碼多了一行代碼,速度卻帶來(lái)了15倍的提升。
有木有興趣來(lái)試一試呢?

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容