冬天鄉下人喜歡烤火取暖,常見的情形就是四人圍著麻將桌,桌底放一盆碳火。有人覺得火不夠大,那加點木炭吧,還不夠,再加點。片刻之後,又覺得火太大,腳都快被烤熟了,那就取出一些木碳……直到火盆裡的火剛剛合適。這樣乙個看似簡單的情形中就包括pid控制系統的四個主要過程:設定目標,測量,比較和執行。結合pid控制器這四個過程來重新闡述上述情形是這樣的:人烤火時所期待的最合適的溫度是我們設定的目標;每個人都是乙個感測器,能感知到溫度的大小(雖然只是模糊的感知)——這是乙個測量的過程;我們感知到的溫度是不是最適合我們,是大還是小——這是乙個比較的過程;比較之後,我們知道火是大還是小了,小了就加點木炭,大了就取出部分木炭——這是乙個執行的過程。不斷重複最後三個過程(如圖1所示),直至使人能感覺到溫度比較合適。
圖1. pid控制過程迴圈
為什麼要控制爬蟲速度,難道像高鐵一樣快不好嗎?其中有兩方面原因:一、對於目標**來說是一種禮貌,如果速度太快,將給伺服器造成過大的負載;二、對於本人來說,抓取速度太快將導致致伺服器禁止訪問,從而丟失大量有效資料,甚至需要重新抓取。那麼如何控制爬蟲抓取網頁的速度,才能使它不至於太快呢?
通常情況下,在每個頁面抓取之間設定較大的延時等待以限制最大訪問頻率,可以保證既不會給伺服器造成過重負擔,也不會因訪問太頻繁而被伺服器禁止,然而這樣的方法將導致網路利用率低,抓取速度慢,對於大量網頁的抓取任務來說,往往是無法忍受的。
圖2. 網路流暢和網路較差時網頁抓取時間對比
圖2是乙個簡化的理想模型,可以很好的說明這個問題,假設某**允許的最大訪問頻率為6頁/分鐘,於是最小時間間隔為10s,這個時間要通過很多次重複試驗來確定(**管理員肯定不會告訴你的)。網路流暢時每個網頁讀取時間為0.5s,為了保證不被伺服器遮蔽,至少要等待9.5s的間隔時間才繼續抓取下乙個頁面,這個9.5s的間隔時間是固定的,即使網路較差時也要等待這麼長的時間。網路較差時,網頁讀取時間為9.5s,再延時等待9.5s,於是每個網頁的讀取時間變為19s,幾乎是網路流暢時的兩倍。而實際上網路較差時的理想情況下,只需要等待0.5s,這時便保持和網路流暢時相同的抓取速度,由此可見這種限制最大速度的方法是很低效的。另外延時等待時間對抓取頻率的影響是很模糊的,延時1s時抓取頻率是100頁/分鐘,那麼延時10s就是10頁/分鐘嗎?很難確定,尤其是在複雜的網路環境中。
要改進上述方法,一種很自然的解決方案就是:使等待時間動態變化,即等於最小時間間隔減去網頁讀取時間,這樣就能保證網頁平均抓取時間在網路流暢和網路較差時都為最小時間間隔。這種方法對於單執行緒的爬蟲訪問小規模**來說也許可行,但在多執行緒分布式的爬蟲訪問大規模**時,整體上的抓取時間由許多並行的抓取任務共同決定,並且各種異常情況(頁面無效或者連線超時)使得抓取時間更加不可計算,這種方法就顯得相當笨拙了。綜合考慮各種因素,顯然我們需要一種模糊的,不需要精確計算的方法來控制爬蟲抓取速度,而且這個速度是很直觀的以頻率(頁/分鐘)來表示——pid控制演算法就是其中一種。
pid控制器控制爬蟲速度的原理簡單來說就是:速度快了,增加延時時間;速度慢了,減小延時時間——是否已經看到了其中與本文開始所描述的烤火情形之間的相似性呢?模擬烤火的情形,設想pid控制爬蟲速度的方案是:
1)初始化:設定初始延時時間t0和比例係數kp(典型值-0.05);
2)目標設定:設定爬蟲速度s,比如40頁/分鐘;
3)測量:統計每分鐘內爬蟲抓取網頁的數量n,可能是32,也可能是100;
4)比較:比較n和s的大小;
5)執行:n如果比s大,說明太快,於是增加延時;n如果比s小,說明太慢,於是減小延時。
該方案的公式化表示如下:
tk=tk-1+kp*(s-n)(3.1)
其中k=1, 2, 3 ... ,tk是第k次設定的延時時間。
不要被表示式嚇住了,它所表達的意思其實就是步驟5)所描述的執行過程:速度太快 (s-n小於0,則kp*(s-n)為正),增加延時 (tk大於tk-1);速度太慢 (s-n大於0, kp*(s-n)為負),減小延時 (tk小於tk-1)。
假設初始延時時間t0為1.0s, 比例係數kp為-0.05,爬蟲速度s設定為40頁/分鐘。如果某次爬蟲抓取網頁的數量n=100,根據3.1式計算的延時值t1=t0+kp*(s-n)=1.0+(-0.05)*(40-100)=4.0;下一次可能的測量值n=30,則計算的延時值t2=4.0-0.05*10=3.5。
圖3. pid控制曲線
圖3是某次實驗中pid控制曲線,下面的資料是這次實驗的詳細記錄,第一列([2012/5/21 1:31:00])是當前時間,第二列(80)是前一分鐘內爬蟲抓取網頁的數量n,第三列(3799)是根據3.1式(實際計算中加入了乙個積分項,稍後詳細說明)計算出來的延時時間(單位為ms),爬蟲速度最終穩定在40頁/分鐘(允許一定的波動)。
[2012/5/21 1:31:00] 80 3799
[2012/5/21 1:32:00] 32 4039
[2012/5/21 1:33:00] 30 3980
[2012/5/21 1:34:00] 30 3720
[2012/5/21 1:35:00] 32 3400
[2012/5/21 1:36:00] 36 3200
[2012/5/21 1:37:00] 36 2920
[2012/5/21 1:38:00] 42 2980
[2012/5/21 1:39:00] 40 2980
[2012/5/21 1:40:00] 40 2980
[2012/5/21 1:41:00] 40 2980
[2012/5/21 1:42:00] 40 2980
[2012/5/21 1:43:00] 40 2980
[2012/5/21 1:44:00] 40 2980
[2012/5/21 1:45:00] 40 2980
[2012/5/21 1:46:00] 40 2980
[2012/5/21 1:47:00] 40 2980
[2012/5/21 1:48:00] 40 2980
[2012/5/21 1:49:00] 39 2910
[2012/5/21 1:50:00] 40 2910
[2012/5/21 1:51:00] 41 2980
[2012/5/21 1:52:00] 39 2930
[2012/5/21 1:53:00] 41 3000
[2012/5/21 1:54:00] 40 3000
[2012/5/21 1:55:00] 39 2930
有了pid控制器,在網路環境允許的範圍內,想讓爬蟲每分鐘抓幾個網頁它就抓幾個,是不是很方便?
式3.1是乙個簡化版本的pid控制器,只用到了比例項(p),加入積分項(i)和微分項(d)後才是乙個完整的pid控制器。pid是三個英文單詞的縮寫,分別代表比例單元(proportion),積分單元(integral)和微分單元(differential),每個單元分別對應著乙個乘積因子kp,ki,kd。加入積分單元和微分單元後,式3.1擴充套件為式4.1,其中sum是誤差項(s-n)的積分(其實就是所有誤差值的和),diff是誤差項的微分(在單位時間內就是前後兩次誤差項的差值)。
tk=tk-1+kp*(s-n)+ki*sum+kd*diff(4.1)
乘積因子kp、ki、kd的設定與具體的應用場景相關,並且需要通過實驗來確定其最佳值。若令ki=0, kd=0,那麼式4.1退化成式3.1。
參考:pid控制器 - 維基百科
pid演算法完全講解
pid演算法理解
PID控制器簡介
pid調節 基於誤差來消除誤差 可以認為是 誤差的過去 i 現在 p 未來 變化趨勢 d的加權和 pid控制器就是根據系統的誤差,利用比例 積分 微分計算出控制量進行控制的。pid控制的不足 1.在實際工業生產過程往往具有非線性 時變不確定,難以建立精確的數學模型,常規的pid控制器不能達到理想的控...
PID控制器開發筆記之五 變積分PID控制器的實現
在普通的pid控制演算法中,由於積分係數ki是常數,所以在整個控制過程中,積分增量是不變的。然而,系統對於積分項的要求是,系統偏差大時,積分作用應該減弱甚至是全無,而在偏差小時,則應該加強。積分係數取大了會產生超調,甚至積分飽和,取小了又不能短時間內消除靜差。因此,如何根據系統的偏差大小改變積分速度...
jmeter控制器 交替控制器
1.簡單使用 如下圖,設定1個執行緒,執行3次 執行結果如下圖 2.巢狀乙個控制器,不勾選忽略子控制器 測試計畫如下圖 巢狀乙個迴圈控制器,迴圈次數設定3次 執行緒組設定1個執行緒,執行5次 執行結果如下圖 總結 交替執行到迴圈控制器時,迴圈執行結束後,在進行下一次的交替。3.巢狀乙個控制器,勾選忽...