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* () { yield largeArray.map(function (e) { return db.col.findById(e).exec() .then(k => { do something with k }) }) }) 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 }) |