Skip to content

性能

🌐 Parallelism and concurrency

Node.js 在处理对原生模块(例如 sharp)的异步调用时,使用 libuv 管理的线程池。

🌐 Node.js uses a libuv-managed thread pool when processing asynchronous calls to native modules such as sharp.

sharp 可以并行处理的最大图片数由 libuv 的 UV_THREADPOOL_SIZE 环境变量控制,默认值为 4。

🌐 The maximum number of images that sharp can process in parallel is controlled by libuv’s UV_THREADPOOL_SIZE environment variable, which defaults to 4.

当使用超过4个物理CPU核心时,在Node.js进程启动前设置这个环境变量,以增加线程池的大小。

🌐 When using more than 4 physical CPU cores, set this environment variable before the Node.js process starts to increase the thread pool size.

export UV_THREADPOOL_SIZE="$(lscpu -p | egrep -v "^#" | sort -u -t, -k 2,4 | wc -l)"

libvips 使用一个共享线程池来避免创建新线程的开销。这个线程池的规模会根据需求增加,也会在空闲时缩小。

🌐 libvips uses a shared thread pool to avoid the overhead of spawning new threads. The size of this thread pool will grow on demand and shrink when idle.

默认情况下,用于同时处理每张图片的线程数与 CPU 核心数相同,除非在使用基于 glibc 的 Linux 系统而没有 jemalloc 或者没有 MALLOC_ARENA_MAX 的情况下,这时默认值是 1,以帮助减少内存碎片。

🌐 The default number of threads used to concurrently process each image is the same as the number of CPU cores, except when using glibc-based Linux without jemalloc or without MALLOC_ARENA_MAX, where the default is 1 to help reduce memory fragmentation.

使用 sharp.concurrency() 来管理每张图片的线程数量。

🌐 Use sharp.concurrency() to manage the number of threads per image.

为了在使用默认的 Linux glibc 内存分配器时减少内存碎片,可以在 Node.js 进程启动前将 MALLOC_ARENA_MAX 环境变量设置为 2 或 4,以减少内存池的数量。

🌐 To reduce memory fragmentation when using the default Linux glibc memory allocator, set the MALLOC_ARENA_MAX environment variable to either 2 or 4 before the Node.js process starts to reduce the number of memory pools.

export MALLOC_ARENA_MAX="2"

🌐 Benchmark

对该模块相对于替代方案的性能进行基准测试。

🌐 A test to benchmark the performance of this module relative to alternatives.

启用缓存(默认)并使用8核以上的机器,尤其是那些L1/L2 CPU缓存较大的机器,可以期望获得更好的libvips性能。

🌐 Greater libvips performance can be expected with caching enabled (default) and using 8+ core machines, especially those with larger L1/L2 CPU caches.

相关(解)压缩库的 I/O 限制通常将决定最大吞吐量。

🌐 The I/O limits of the relevant (de)compression library will generally determine maximum throughput.

🌐 Contenders

  • jimp v1.6.1 - 纯 JavaScript 图片处理。
  • imagemagick v0.1.3 - 仅支持文件系统,并且“已经很久没有维护了”。
  • gm v1.25.1 - 完整功能封装了 GraphicsMagick 的 gm 命令行工具,但“已经被淘汰”。
  • sharp v0.35.0 / libvips v8.18.2 - 为了确保公平比较,libvips 内的缓存已被禁用。

🌐 Environment

  • AWS EC2 us-west-2 c8a.xlarge(4x AMD EPYC 9R45)
  • Ubuntu 25.10
  • Node.js 24.15.0
  • AWS EC2 us-west-2 c8g.xlarge(4x ARM Graviton4)
  • Ubuntu 25.10
  • Node.js 24.15.0

🌐 Task: JPEG

解压一个2725x2225的JPEG图片,使用Lanczos 3重采样(如果可用)调整大小到720x588,然后以“质量”设置80压缩为JPEG。

🌐 Decompress a 2725x2225 JPEG image, resize to 720x588 using Lanczos 3 resampling (where available), then compress to JPEG at a “quality” setting of 80.

注意:jimp 不支持 Lanczos 3,所以改用双三次重采样。

🌐 Note: jimp does not support Lanczos 3, bicubic resampling used instead.

🌐 Results: JPEG (AMD64)

包 I/O 操作/秒 加速比
jimp 缓冲区 3.44 1.0
jimp 文件 3.65 1.1
imagemagick 文件 16.23 4.7
gm 缓冲区 20.92 6.1
gm 文件 21.04 6.1
sharp 流 82.87 24.1
sharp 文件 88.21 25.6
sharp 缓冲区 89.63 26.1

🌐 Results: JPEG (ARM64)

包 I/O 操作/秒 加速比
jimp 缓冲区 2.20 1.0
jimp 文件 2.45 1.1
imagemagick 文件 5.85 2.7
gm 文件 13.72 6.2
gm 缓冲区 13.82 6.3
sharp 流 49.82 22.6
sharp 文件 52.42 23.8
sharp 缓冲区 53.83 24.5

🌐 Task: PNG

解压一个2048x1536的RGBA PNG图片, 预乘alpha通道, 使用Lanczos 3重采样(如果可用)调整大小到720x540, 取消预乘然后以默认zlib压缩等级6压缩为PNG,不使用自适应过滤。

🌐 Decompress a 2048x1536 RGBA PNG image, premultiply the alpha channel, resize to 720x540 using Lanczos 3 resampling (where available), unpremultiply then compress as PNG with a “default” zlib compression level of 6 and without adaptive filtering.

注意:jimp 不支持预乘/反预乘。

🌐 Note: jimp does not support premultiply/unpremultiply.

🌐 Results: PNG (AMD64)

包 I/O 每秒操作次数 加速比
imagemagick 文件 10.37 1.0
gm 文件 13.35 1.3
jimp 缓冲区 17.04 1.6
jimp 文件 17.15 1.7
sharp 文件 47.17 4.5
sharp 缓冲区 47.74 4.6

🌐 Results: PNG (ARM64)

软件包 输入/输出 每秒操作数 加速比
imagemagick 文件 4.39 1.0
gm 文件 9.45 2.2
jimp 缓冲区 10.36 2.4
jimp 文件 10.52 2.4
sharp 文件 28.04 6.4
sharp 缓冲区 28.57 6.5

🌐 Running the benchmark test

需要 Docker。

🌐 Requires Docker.

git clone https://github.com/lovell/sharp.git
cd sharp/test/bench
./run-with-docker.sh