由nodejs gzip压缩引起的性能实验测试

环境

系统 CPU 内存 硬盘
windows 10 Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz (6核12线程) 32GB Pcie3.0 SSD
ubuntu 20.04 Intel(R) Xeon(R) Gold 6133 CPU @ 2.50GHz (4核) 4GB HDD

测试案例

rust 中文文档作为测试案例,共有170多个文件,总体积10M+,最大文件3M+(只有1个),最小文件1K, 使用 vitest 做基准测试。

实现代码

ts 复制代码
// src/gzip.ts

import fs from 'node:fs'
import fsp from 'node:fs/promises'
import { promisify } from 'node:util'
import zlib from 'node:zlib'
import PQueue from 'p-queue'

function gzipCompressSync(inputPath: string, outputPath: string) {
  fs.writeFileSync(outputPath, zlib.gzipSync(fs.readFileSync(inputPath)))
}

async function gzipCompressAsync(inputPath: string, outputPath: string): Promise<void> {
  const buffer = await fsp.readFile(inputPath)
  const data = await promisify(zlib.gzip)(buffer)
  await fsp.writeFile(outputPath, data)
}

function gzipCompressStream(inputPath: string, outputPath: string): Promise<void> {
  return new Promise<void>((resolve, reject) => {
    const readStream = fs.createReadStream(inputPath)
    const writeStream = fs.createWriteStream(outputPath)
    const gzip = zlib.createGzip({ level: zlib.constants.Z_BEST_COMPRESSION })

    readStream.pipe(gzip).pipe(writeStream).on('finish', resolve).on('error', reject)
  })
}

// 同步
export function fn1(files: string[]) {
  files.forEach(filePath => {
    gzipCompressSync(filePath, filePath + '.gz')
  })
}

// 异步
export async function fn2(files: string[]): Promise<void> {
  await Promise.all(files.map(filePath => gzipCompressAsync(filePath, filePath + '.gz')))
}

// 异步 + 并发控制
export async function fn3(files: string[]): Promise<void> {
  const queue = new PQueue({ concurrency: 4 })
  files.forEach(filePath => {
    queue.add(() => gzipCompressAsync(filePath, filePath + '.gz'))
  })
  await queue.onIdle()
}

// 异步流式
export async function fn4(files: string[]): Promise<void> {
  await Promise.all(files.map(filePath => gzipCompressStream(filePath, filePath + '.gz')))
}

// 异步流式 + 并发控制
export async function fn5(files: string[]): Promise<void> {
  const queue = new PQueue({ concurrency: 4 })
  files.forEach(filePath => {
    queue.add(() => gzipCompressStream(filePath, filePath + '.gz'))
  })
  await queue.onIdle()
}

测试代码

ts 复制代码
// gzip.bench.ts

import { bench, describe } from 'vitest'
import fg from 'fast-glob'
import { fn1, fn2, fn3, fn4, fn5 } from 'src/gzip'

const files = fg.sync(['trpl-zh-cn-gh-pages/**/*.(html|css|js|svg|txt|ttf|woff|woff2)'])

describe('gzip', () => {
  bench('同步', () => fn1(files))

  bench('异步', () => fn2(files))

  bench('异步 + 并发控制', () => fn3(files))

  bench('异步流式', () => fn4(files))

  bench('异步流式 + 并发控制', () => fn5(files))
})

测试结果

windows10

名称 hz min max mean p75 p99 p995 p999 rme
同步 3.2818 295.25 320.24 304.71 308.72 320.24 320.24 320.24 ±1.71%
异步 7.4271 128.40 144.22 134.64 139.24 144.22 144.22 144.22 ±2.75%
异步 + 并发控制 8.3062 115.85 136.76 120.39 120.50 136.76 136.76 136.76 ±3.79%
异步流式 2.7015 362.85 392.05 370.16 371.38 392.05 392.05 392.05 ±1.77%
异步流式 + 并发控制 2.7968 346.35 391.09 357.55 359.39 391.09 391.09 391.09 ±2.54%
bash 复制代码
 BENCH  Summary
 异步 + 并发控制 - bench/gzip.bench.ts > gzip
    1.12x faster than 异步
    2.53x faster than 同步
    2.97x faster than 异步流式 + 并发控制
    3.07x faster than 异步流式

说明:在windows10下增加 concurrency ,对性能提升不明显,甚至会起负作用,设为4时,效果已经不错

ubuntu 20.04

名称 hz min max mean p75 p99 p995 p999 rme
同步 2.5521 379.56 406.43 391.83 402.72 406.43 406.43 406.43 ±1.93%
异步 3.8680 239.57 279.61 258.53 267.82 279.61 279.61 279.61 ±3.36%
异步 + 并发控制 3.1925 287.61 350.28 313.24 319.58 350.28 350.28 350.28 ±4.17%
异步流式 1.2683 762.20 817.18 788.47 804.72 817.18 817.18 817.18 ±1.87%
异步流式 + 并发控制 1.2323 785.02 834.35 811.50 823.15 834.35 834.35 834.35 ±1.42%
bash 复制代码
BENCH  Summary   
异步 - bench/gzip.bench.ts > gzip
    1.21x faster than 异步 + 并发控制     
    1.52x faster than 同步     
    3.05x faster than 异步流式     
    3.14x faster than 异步流式 + 并发控制

说明:在ubuntu下增加 concurrency ,会使结果逐渐接近不做并发控制的方案,大约在32时,跟不做并发控制的结果趋于一致。看起来跟cpu核心数、libuv线程池大小都毫无关联,原因跟硬盘、cpu、系统可能都有关系。

相关推荐
漂流瓶jz8 小时前
让数据"流动"起来!Node.js实现流式渲染/流式传输与背后的HTTP原理
前端·javascript·node.js
陪我一起学编程10 小时前
关于nvm与node.js
vue.js·后端·npm·node.js
程序猿小D10 小时前
第22节 Node.js JXcore 打包
开发语言·人工智能·vscode·node.js·c#
2401_8784545310 小时前
node.js的初步学习
学习·node.js
古韵14 小时前
alova 3.3.0 发布:开发体验提升的重大更新
node.js·nuxt.js·next.js
不想说话的麋鹿15 小时前
《NestJS 实战:RBAC 系统管理模块开发 (一)》
前端·node.js·全栈
Lstmxx16 小时前
Electron:使用数据流的形式加载本地视频
前端·electron·node.js
LeeAt17 小时前
npm:详细解释前端项目开发前奏!!
前端·node.js·html
chxii17 小时前
1.6 http模块nodejs 对比 go
http·node.js