由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、系统可能都有关系。

相关推荐
HWL56791 小时前
输入框内容粘贴时 &nbsp; 字符净化问题
前端·vue.js·后端·node.js
. . . . .1 天前
Node.js 的替代品Bun
node.js
一只月月鸟呀1 天前
AI使用 Node.js modbus-serial 搭建一个可交互的 Modbus TCP 主站与从站 Demo
网络协议·tcp/ip·node.js
学渣y1 天前
nvm下载node版本,npm -v查看版本报错
前端·npm·node.js
灰太狼大王灬2 天前
Node.js 本地服务部署、常驻及调用完整笔记
笔记·node.js
你的电影很有趣2 天前
lesson71:Node.js与npm基础全攻略:2025年最新特性与实战指南
前端·npm·node.js
闲蛋小超人笑嘻嘻2 天前
前端面试十四之webpack和vite有什么区别
前端·webpack·node.js
特立独行的猫a2 天前
JSNES游戏模拟器在 Node.js 环境下的测试使用及高清显示优化
游戏·node.js·nes·jsnes
huangql5202 天前
基于前端+Node.js 的 Markdown 笔记 PDF 导出系统完整实战
前端·笔记·node.js
谢尔登3 天前
【Nest】基本概念
javascript·node.js·express