性能
并行性和并发性
Section titled “并行性和并发性”🌐 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
任务:JPEG
Section titled “任务:JPEG”🌐 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.
结果:JPEG(AMD64)
Section titled “结果:JPEG(AMD64)”🌐 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 |
结果:JPEG(ARM64)
Section titled “结果:JPEG(ARM64)”🌐 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 |
任务:PNG
Section titled “任务:PNG”🌐 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.
结果:PNG(AMD64)
Section titled “结果:PNG(AMD64)”🌐 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 |
结果:PNG(ARM64)
Section titled “结果:PNG(ARM64)”🌐 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 |
运行基准测试
Section titled “运行基准测试”🌐 Running the benchmark test
需要 Docker。
🌐 Requires Docker.
git clone https://github.com/lovell/sharp.gitcd sharp/test/bench./run-with-docker.sh