前端AVIF编码开多线程快两三倍,speed调到8就不快了

在网页里点一下「导出 AVIF」,图是一张 1200 万像素的照片,要等将近四秒文件才出来。这是我在自己搭的测试页上量到的,机器是一台 Apple M4 的 Mac,系统是 macOS,浏览器是 Chromium 149,三次分别是 3802、3754、3747 毫秒。我日常的活绕不开商品图上传,想知道把转 AVIF 这一步挪到浏览器里做,一张图要等多久,换成多线程又能省下多少,就先拿一张图试了试。

开始之前把几个词说清楚。AVIF 是一种比较新的图片格式。把一堆像素压成某种格式的文件,干这个活的程序叫编码器。我试的四个浏览器里有三个不会自己往外写 AVIF,所以页面得自带一个编码器。我用的是 @jsquash/avif 2.1.1,它把 libavif v1.0.1 这个库编成了 WASM。WASM 可以理解成浏览器能直接运行的一种二进制程序,别的语言写的库靠它搬进网页。这个包里的编码器有两份,一份单线程,一份多线程。线程就是干活的人手,单线程好比一摞卷子只有一个老师在改,多线程是把卷子分给几个老师同时改。我这台机器在 Chromium 里报的是 10 个核,我原先想当然地觉得换成多线程那份能快上好几倍。量出来没有那么多。

用的图是维基共享资源上 Jakub Fryš 拍的一张湖景,CC BY-SA 4.0 授权。图不是我拍的。我在测试页里把它缩成五档大小,参数全用这个包的默认值,也就是质量 50、speed 6、4:2:0,每档编三次。Chromium 149 里,200 万像素单线程是 696、696、673 毫秒,多线程是 327、324、323 毫秒。800 万像素是 2.6 秒对 1 秒出头。1200 万像素就是开头那个 3.8 秒左右,多线程三次是 1441、1410、1468 毫秒,约 1.4 秒。1600 万像素是 4.9 秒对 1.85 秒上下。Chrome 155 的读数和 Chromium 几乎贴在一起。WebKit 26.5 的多线程还略快一点,1200 万像素是 1279、1260、1251 毫秒。按各档的中间值算,多线程在 Chromium 和 Chrome 里快 1.9 到 2.7 倍,在 WebKit 里快 2.0 到 3.2 倍,说成快两三倍差不多。

图里每一档上面那条是单线程,下面那条是多线程,标的是三次里的中间值。看 1200 万像素那一档就够了,3,754 毫秒对 1,441 毫秒。

这些毫秒数量的只是 encode() 这一个调用,解码原图、缩放、取像素、把结果交回页面都没算进去。编码我都放在 Worker 里跑,Worker 是浏览器给网页开的后台线程。测试页里挑文件和计时的就是下面几行:

js 复制代码
const glue = useThreads ? 'avif_enc_mt.js' : 'avif_enc.js';
const enc = await loadEnc(glue);
const t0 = performance.now();
const bytes = enc.encode(pixels, width, height, { ...defaults, speed: 6 });
const cost = Math.round(performance.now() - t0); // 只算这一个调用

我用的 Firefox 151 测试版本里,两份编码器都慢出一大截。正式发布版我没复核,原因也没查,这一篇就不把它算进倍数里。

多线程那份不是换个文件名就能用,它要求页面处在「跨源隔离」状态。说白了就是服务器返回页面的时候多带两个响应头,响应头是服务器随内容一起发回来的几行说明。浏览器看到之后会把这个页面和别的来源隔开,页面里 crossOriginIsolated 这个值就变成 true。我的测试页是本机起的一个小服务,返回每个文件时都带着 Cross-Origin-Opener-Policy: same-origin 和 Cross-Origin-Embedder-Policy: require-corp 这两行,四个浏览器里这个值都是 true。不带这两个头的时候,多线程那份是报错,是悄悄退回单线程,还是别的什么表现,我没有测,这里不乱说。另外这两个头是对整个页面生效的。我的测试页上全是自己的文件,页面里要是嵌了别的域名的图片、脚本或者 iframe,会不会受影响?这个我也没试。改响应头在我这儿算影响面比较大的改动,真要上之前我会把这一项单独验一遍。

快 2 到 3 倍还有一个前提,就是 speed 停在默认的 6。speed 是编码器的一个档位,数字越大编得越快。我把同一张图固定在 200 万像素,把 speed 调到 8 和 10 各跑了三次。speed 8 时单线程是 230、163、161 毫秒,多线程是 239、174、173 毫秒。speed 10 时单线程是 156、103、100 毫秒,多线程是 204、149、146 毫秒。拿第二次的读数比,174 对 163,149 对 103,多线程不比单线程快,speed 10 那一档还慢了一些。为什么会这样我没去查。画质也要补一句,speed 8、10 编出来的画质我没有量,这两组数只能说明线程的事,不能拿来当「该把 speed 调高」的依据。

我还拿一个现成的在线工具看了看它带的是哪一份编码器。我用的是图映 ImgIng(imging.cn/),一个在线处理图片的... Chromium 149 里把那张湖景的五档 PNG 各转了一次 AVIF。从网络请求看,它在我选中 AVIF 的那一刻就开始拉编码器,拉的是 avif_enc_mt.wasm,也就是多线程那份,gzip 压缩后传输 1,135,337 字节,约 1.1 MB。第一次转换时按钮上会先出现「初始化核心...」,后面几次没有再出现。从点下转换到按钮恢复,1200 万像素那档等了 1579 毫秒,1600 万像素那档等了 1630 毫秒。这两个数不能和我上面那些对着比,口径不一样。它是我从页面外面掐的整段等待,读图和界面更新都在里面,画质默认停在 52,和我的 50 也不一样,每档也只跑了一次。它内部怎么写的我没有看。

这是第一次转换中途截的右侧面板。AVIF 按钮角上标着「按需 WASM」,画质滑杆停在 52,下面的大按钮正显示「初始化核心...」,最底下一行写着模块下载完成、正在编译本地编码核心。

回到我自己的事上。我后来定下来的顺序是,先在页面的控制台里打一下 crossOriginIsolated,是 false 就先不考虑多线程那份。是 true 的话,再用自己业务里常见尺寸的图,把两份编码器在打算用的 speed 上各跑三次,看倍数还在不在。两份文件体积差不多,单线程 3,485,872 字节,多线程 3,534,665 字节,我自己用 gzip 压了一下都在 1.1 MB 上下。选哪份主要看那两个头加不加得上。这些数我只在一台 M4 上量过,换一台机器、换一个浏览器版本都会变。没有那两个头时的表现也还空着。

相关推荐
孟陬8 小时前
Foobar 技术周刊#160:大模型让大规模形式化软件验证成为现实丨AI写C++代码之后会发生什么?丨我们真的需要alpha() 函数吗丨重试,有时会让故障更
前端·后端·typescript
flash俊杰8 小时前
屏幕感知双通道:截图之外,为什么还要一份 UIA 控件清单
前端
熟的生菜8 小时前
从零造一个腱绳驱动灵巧手——仿真器篇3:VTK 渲染与 3D 交互——看得见、点得着、转得动
前端
Henry-SAP10 小时前
SAP PP中的核心业务流程——离散制造、重复制造、流程制造三大模式解析
前端·数据库·人工智能·制造
徐小夕10 小时前
下载量超 30 万的开源智能体 Prime Agent:它把自己从 TypeScript 重写成了 Rust
前端·vue.js·github
Zhao-Jichao10 小时前
AI Prompting for Everyone 课程笔记 - P20 实验与期末项目 Lab and Final Project
前端·人工智能·笔记
Moment10 小时前
为什么这么多 Agent Harness 都选择 TypeScript
前端·后端·面试
toooooop810 小时前
CRMEB 故障排查笔记:安全网关只放行 GET/POST 怎么办
前端·javascript·vue.js·thinkphp6·crmeb
涛涛ing11 小时前
我现在最怕的不是 AI 写不出代码,是它写得太快,快到我不好意思说“等一下”
前端
AllData公司负责人11 小时前
【产品便捷使用一】AIIData 数据中台:企业基础版核心能力支持,一站式全链路数据处理实操指南
大数据·前端·数据治理·数据可视化·数据开发·数据服务·数据接入