无法完成由于内存不足导致的承诺

无法完成由于内存不足导致的承诺

问题描述:

我有一个脚本来擦去~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

您正试图并行运行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