2016-07-25 64 views
1

我有一個腳本來擦去~1000個網頁。我使用Promise.all解僱他們在一起,並將其返回時,所有頁面都做:無法完成由於內存不足導致的承諾

Promise.all(urls.map(url => scrap(url))) 
    .then(results => console.log('all done!', results)); 

這是甜的,正確的,除了一臺件事 - 機器進入了內存併發的,因爲要求。我使用jsdom進行報廢,它很快佔用了幾GB的內存,考慮到它實例化了數百個window,這是可以理解的。

我有一個想法來解決,但我不喜歡它。也就是說,變更控制流程不使用Promise.all,但我的鏈條承諾:

let results = {}; 
urls.reduce((prev, cur) => 
    prev 
     .then(() => scrap(cur)) 
     .then(result => results[cur] = result) 
     //^not so nice. 
, Promise.resolve()) 
    .then(() => console.log('all done!', results)); 

,因爲它的鏈接這並不像Promise.all好......不是高性能,並且返回的值必須被存儲供以後處理。

有什麼建議嗎?我應該改進控制流程,還是應該改進scrap()中的mem使用情況,還是讓節點節流mem分配?

+0

我不明白你的意思了「*未高性能的,因爲它是鏈接*」 – Bergi

+0

順便說一下,它需要'。那麼(()=>廢料( cur))' – Bergi

+0

@Bergi也許我錯了。我認爲緩慢的部分是對網址的請求。在鏈接版本中,您只能在完成之前網址上的所有剪貼工作後才能觸發下一個請求。在Promise.all版本中,它們都可以啓動(發送http請求當然是異步的),並在返回時處理。 – Boyang

回答

5

您正試圖並行運行1000個網頁抓取。你需要選擇一個明顯小於1000的數字,並且一次只運行N個,這樣你在這樣做的時候消耗更少的內存。您仍然可以使用承諾來跟蹤他們全部完成的時間。

Bluebird's Promise.map()可以通過將併發值作爲選項傳遞給您。或者,你可以自己寫。

我有一個想法解決,但我不喜歡它。也就是說,變更控制流程 不使用Promise.all,但我的鏈條承諾:

你想要的是個運算在同一時間的航班。排序是一種特殊情況,其中N = 1往往比平行排列其中一些要慢得多(可能與N = 10)。

這不如Promise.all ...好,因爲它被鏈接, 和返回的值必須存儲以備後續處理。

如果存儲值是你內存問題的一部分,你可能不得不在任何地方將它們存儲在內存不足的地方。您將不得不分析存儲結果使用的內存量。

有什麼建議嗎?我應該改善控制流程,還是應該改善報廢()中的內存使用量,或者是否有辦法讓節點節流mem 分配?

使用Bluebird's Promise.map()或自己寫一些類似的東西。並行編寫並行執行N個操作並且保持所有結果順序的東西不是火箭科學,但要做到這一點還是有點工作的。我已經在另一個答案中提出過它,但現在似乎無法找到它。我會繼續尋找。

發現我的現有技術相關的答案在這裏:Make several requests to an API that can only handle 20 request a minute

+0

添加鏈接到解決這個問題的參考代碼。 – jfriend00

+0

解決了我的問題!藍鳥的附加功能非常有用 – Boyang

相關問題