网络爬虫:采用“负载均衡”策略来优化网络爬虫
前言:
? 這里說的負(fù)載均衡并非大家熟悉的網(wǎng)絡(luò)中的負(fù)載均衡。
? 只是這里我使用了和負(fù)載均衡同樣的一種思維來優(yōu)化程序罷了,其實(shí)就是壓力分?jǐn)偂?/span>
問題描述:
? 對(duì)于上一篇《分離生產(chǎn)者和消費(fèi)者來優(yōu)化爬蟲程序》博客中遺留的問題:線程阻塞。
? 當(dāng)我們的程序運(yùn)行到一定時(shí)間之后,會(huì)出現(xiàn)線程池中的500條線程不夠用的情況,進(jìn)而程序長期處于等待的狀態(tài)。
壓力測(cè)試實(shí)驗(yàn):
? 本實(shí)驗(yàn)基于之前的爬蟲程序,線程池中的線程最大為320條。下面是對(duì)在主線程中以不同時(shí)間間隔執(zhí)行程序的測(cè)試結(jié)果:
sleep 300ms
sleep 500ms
sleep 1000ms
內(nèi)存使用狀態(tài)圖:
代碼優(yōu)化邏輯:
1.python代碼優(yōu)化
import sys reload(sys) sys.setdefaultencoding('utf8') from time import clock, sleep import threadingfrom list_web_parser import ListWebParser import get_html_response as gethdef visited_html(html):myp = ListWebParser()get_html = geth.get_html_response(html)myp.feed(get_html)link_list = myp.getLinkList()myp.close()for item in link_list:if item[0] and item[1]:print item[0], '$#$', item[1]global thread_done_flagthread_done_flag = Truedef count_down():start = clock()while True:sleep(1)end = clock()if int(end - start) >= 2:print 'TIME OUT'global thread_done_flagthread_done_flag = Truebreakthread_done_flag = Falsedef start_work(url):thread1 = threading.Thread(target=visited_html, args=(url,))thread2 = threading.Thread(target=count_down)thread1.setDaemon(True)thread2.setDaemon(True)thread1.start()thread2.start()while not thread_done_flag:''if __name__ == "__main__":if not sys.argv or len(sys.argv) < 2:print 'You leak some arg.'start_work(sys.argv[1])? 這段代碼做了一件事,主線程跟隨第一個(gè)子線程結(jié)束而結(jié)束。
? 目的是為了讓程序在1秒鐘之內(nèi)結(jié)束運(yùn)行,而超過1秒的html解析,我們將拋棄。我想這是合理的。因?yàn)槲覀儾豢赡茏孭ython一直占用我們的線程資源,這樣很快線程就會(huì)出現(xiàn)阻塞。而且,隨著我們解析HTML的線程數(shù)的增加。CPU的消耗也很快,這樣我們的計(jì)算機(jī)就會(huì)出現(xiàn)卡頓的情況。
2.Java代碼優(yōu)化
public void visittingUrl(String startAddress) {// url 合法性判斷if (startAddress == null) {return;}// 種子url 入庫SpiderBLL.insertEntry2DB(startAddress);// 解析種子urlPythonUtils.fillAddressQueueByPython(mUnVisitedQueue, startAddress, 0);if (mUnVisitedQueue.isQueueEmpty()) {System.out.println("Your address cannot get more address.");return;}boolean breakFlag = false;int index = 0;startThread();while (!breakFlag) {WebInfoModel model = mUnVisitedQueue.poll();if (model == null) {System.out.println("------ 此URL為NULL ------");continue;}// 判斷此網(wǎng)站是否已經(jīng)訪問過if (DBBLL.isWebInfoModelExist(model)) {// 如果已經(jīng)被訪問,進(jìn)入下一次循環(huán)System.out.println("已存在此網(wǎng)站(" + model.getName() + ")");continue;}poolQueueFull(mThreadPool);System.out.println("LEVEL: [" + model.getLevel() + "] NAME: " + model.getName());mThreadPool.execute(new ParserRunner(mResultSet, model, index++, mResultMap));SystemBLL.cleanSystem(index);// 對(duì)已訪問的address進(jìn)行入庫DBBLL.insert(model);model = null;SystemBLL.sleep(300);}mThreadPool.shutdown();}? Java代碼的代碼主要體現(xiàn)在,我們每次調(diào)用Python進(jìn)行解析HTML時(shí),都會(huì)sleep 300毫秒。這樣我們CPU的壓力就轉(zhuǎn)移到時(shí)間上了。而這300毫秒其實(shí)對(duì)整體程序的影響不大,算是優(yōu)點(diǎn)大于缺點(diǎn)吧。
關(guān)于上一篇:
1.覆蓋equals時(shí)總要覆蓋hashCode
? 我們需要覆蓋WebInfoModel的equals和hashCode方法,目的是我們把這個(gè)對(duì)象保存到HashSet中,需要保證它的唯一性。那么我們就必須自己來寫一些唯一性的策略:重寫equals方法。而重寫equals時(shí),必須要重寫hashCode方法。關(guān)于這一點(diǎn),大家可以參看筆者的另一篇博客《Effective Java:對(duì)于所有對(duì)象都通用的方法》
@Overridepublic int hashCode() {return (name.hashCode() + address.hashCode() + level);}@Overridepublic boolean equals(Object obj) {if (!(obj instanceof WebInfoModel)) {return false;}if (((WebInfoModel)obj).getName() == name && ((WebInfoModel)obj).getAddress() == address && ((WebInfoModel)obj).getLevel() == level) {return true;}return false;}
遺留的問題:
1.python無故停止運(yùn)行
下一步的目標(biāo):
1.解決python程序停止運(yùn)行的Bug
2.分布式
(終于,終于可以開始利用分布式來優(yōu)化我的蜘蛛程序了。想想還有一點(diǎn)小激動(dòng)呢 ^_^)
總結(jié)
以上是生活随笔為你收集整理的网络爬虫:采用“负载均衡”策略来优化网络爬虫的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 网络爬虫:分离生产者和消费者来优化爬虫程
- 下一篇: 网络爬虫:URL去重策略之布隆过滤器(B