
co(function* () { yield largeArray.map(function* (e) { const k = yield db.col.findById(e).exec() do something with k }) }) Promise.map(largeArray, (e) => { return db.col.findById(e).exec() .then(k => { do something with k }) }) 这上面用的库有
完成的操作就是遍历 id array ,然后把数据从 mongodb 从取出来操作下。但是经过测试,发现 snippet1 会导致内存溢出,但是 snippet2 不会。感觉好像 snippet1 在function* (){}生命周期结束之后,不会马上释放内存。没有研读过tj/co的源码,求大神指点
我重新看了一下代码,发现snippet2是这样的
Promise.map(largeArray, (e) => { return db.col.findById(e).exec() .then(k => { do something with k }, {concurrency: 10}) }) 所以问题的根源还是largeArray太大了,同时去数据库发起太多查询,导致内存溢出。然后用了promise之后因为限制了查询一次就发起10个,等这10查询完了再进行下一个批次查询。所以没有内存溢出。
但是还是有一个问题我没搞明白的是:
我的mongoose设置了poolSize是10,所以同一时间建立的数据库连接就是10个,那么也就是同一时间只能进行10次查询,那为什么snippet1会内存溢出呢?
1 zbinlin 2017-02-21 17:33:02 +08:00 把 snippet1 里的 generator 也换成 promise 试试: co(function*(){ yieldlargeArray.map(function(e){ returndb.col.findById(e).exec() .then(k=>{ dosomethingwithk }) }) }) PS: 话说你的 largeArray 究竟有多大呀? |
2 binux 2017-02-21 17:43:03 +08:00 你的 snippet1 真的 work 吗?你只给 yield largeArray.map 包了 co , largeArray.map 也支持 generator ? |
4 ufo22940268 OP @zbinlin largeArray 也不会很大,就几万,但是中间查询的结果数据量比较大 |
5 cheetah 2017-02-21 18:18:25 +08:00 原因是,在 snippet1 中, largeArray.map 并不会等所有 callback 执行完后才返回,也就是说 Array.prototype.map 并没有 『如果 callback 返回的是个 Promose 则等待』的功能,这种情况就应该用 Promise.map |
6 binux 2017-02-21 18:56:28 +08:00 |
7 zbinlin 2017-02-21 19:01:59 +08:00 @binux 如果 snippet2 Promise 用的是 bluebird ,面里的 Promise.map 也是并行执行的: http://bluebirdjs.com/docs/api/promise.map.html |
8 binux 2017-02-21 19:06:03 +08:00 @zbinlin #7 那就是 snippet1 的 `do something with k` return k 了, snippet2 没有 |
9 cheetah 2017-02-21 19:09:20 +08:00 对 co 不太熟,我把它转成 async/await 的形式是这样没错吧? await largeArray.map(async (e) => { const k = await db.col.findById(e).exec() do something with k }) |