简化需求
需要读取很多文件, 将其中内容读出后, 获取所有文件内容总长度
数据表现有一些波动是因为笔记本电压或后台影响, 但是优化效果是一致的
将2500ms的任务优化到400ms左右
最简单的同步读
function getLen(x) {
return fs.readFileSync(path.join(root, x, x + '.json'), 'utf8').length
}
function run() {
let st = +new Date()
let sum = names.reduce(
(pre, cur) => pre + getLen(cur)
, 0
)
console.log(+new Date() - st, sum)
}
for (let i = 0; i < 10; i++)
run()
两万个文件, 基本上都是2500ms
2860 18423803
2516 18423803
2501 18423803
2513 18423803
2502 18423803
2525 18423803
2478 18423803
2490 18423803
2586 18423803
2610 18423803
简单单个异步
迭代器和rxjs使用异步读, 能快30% 左右, 使用异步的文件时, 有文件数目的最大限制, 而且同时多异步文件数目测试中16个左右就到了极限, 可能是我这边的文件比较小, 都是2~10k, 可能在大文件上会有优势吧
function* getName() {
for (let x of names)
yield path.join(root, x, x + '.json')
}
function run() {
let subject = new Subject()
let g = getName()
let sum = 0
let cnt = 0
let st = +new Date()
subject.subscribe(
x => {
fs.readFile(x.value, 'utf8', (err, data) => {
cnt++
sum += data.length
if (cnt === names.length) {
console.log('end', +new Date() - st, sum)
return
}
subject.next(g.next())
})
}
)
subject.next(g.next())
}
setInterval(
run, 3000
)
// end 1835 18423803
// end 1771 18423803
// end 1761 18423803
// end 1741 18423803
多个异步Promise
使用promise多个, 为了避免v8 优化, 正反跑一边, 如果每次只执行一个异步流, 那么就会退化到简单异步, 时间也是两秒多, 也能看到目前的需求下, 增加个数只会在一开始有极大提升, 后面几乎没有太多作用
不过效果已经提高了四倍多
let st = +new Date()
const names = fs.readdirSync(root).slice(0, 20000)
function getLen(x) {
return new Promise(
resolve => {
let p = path.join(root, x, x + '.json')
fs.readFile(p, 'utf8', (err, data) => {
resolve(data.length)
})
}
)
}
async function arr(n = 1) {
let arr = []
let sum = 0
let cnt = 0
for (let i of names) {
cnt++
arr.push(i)
if (arr.length === n || cnt === names.length) {
// console.log(n, cnt, arr.length, names.length)
let res = await Promise.all(arr.map(i => getLen(i)))
sum += res.reduce((pre, cur) => pre + cur, 0)
arr = []
}
}
let ed = +new Date()
console.log('sum', n, sum, ed - st)
return ed - st
}
async function start() {
let t = []
// for (let i = 127; i > 0; i -= 2) {
for (let i = 1; i < 32; i += 2) {
st = +new Date()
t.push(await arr(i))
}
console.log(t.join(','))
}
start()
// sum 1 18423803 1817
// sum 3 18423803 736
// sum 5 18423803 460
// sum 7 18423803 467
// sum 9 18423803 394
// sum 11 18423803 406
多异步优化
上面的多异步有一个小的优化点, 比如一次执行n个异步, Promise.all 的时间是n个异步最长的时间, 每次保持异步队列长度固定, 一旦有一个异步执行完成, 则重新加一个进去, 大概能再优化几毫秒
const root = 'D:/data/扇贝单词/word_json_v2'
const names = fs.readdirSync(root).slice(0, 20000)
function getLen(x) {
return new Promise(
resolve => {
let p = path.join(root, x, x + '.json')
fs.readFile(p, 'utf8', (err, data) => {
resolve(data.length)
})
}
)
}
function* getName() {
for (let i of names)
yield i
}
let g = getName()
let size = 16
let sum = 0
let cnt = 0
function summary() {
let next = g.next()
if (next.done) {
return
}
getLen(next.value).then(
(data) => {
sum += data
cnt++
if (cnt === names.length) {
console.log('===', +new Date() - st, sum)
return
}
summary()
}
)
}
let st = +new Date()
for (let i = 0; i < size; i++) {
summary()
}
// === 377 18423803
总结
通过使用rxjs, 生成器, promise 等方法做这次优化, 也算是对这些技术点有了更多的了解, 以后要多思考~
来源:oschina
链接:https://my.oschina.net/ahaoboy/blog/3167490