跳至内容
博客
SWC 和 Babel 的性能比较

SWC 和 Babel 的性能比较

2020 年 1 月 31 日作者:DongYoon Kang

JavaScript 是单线程的。JS 线程不适合进行繁重的计算。让我们谈谈 babelswc,它们都是计算密集型的。

同步基准测试

让我们对单核工作负载进行基准测试。请注意,这使用了 transformSync,它在实际应用中很少有用。

[transform]
  swc (es3) x 616 ops/sec ±4.36% (88 runs sampled)
  swc (es2015) x 677 ops/sec ±2.01% (90 runs sampled)
  swc (es2016) x 1,963 ops/sec ±0.45% (93 runs sampled)
  swc (es2017) x 1,971 ops/sec ±0.35% (94 runs sampled)
  swc (es2018) x 2,555 ops/sec ±0.35% (93 runs sampled)
  swc-optimize (es3) x 645 ops/sec ±0.40% (90 runs sampled)
  babel (es5) x 34.05 ops/sec ±1.15% (58 runs sampled)

SWC 非常快。虽然 swc (es3)babel (es5) 做了更多工作,但 swc (es3)babel (es5) 更快。

真实世界基准测试

transformSynctransformFileSync 在实际应用中很少使用,因为它会阻塞当前线程。 await Promise.all() 经常使用,并且比

for (const promise of promises) {
  await promise;
}

让我们使用 Promise.all() 为实际应用场景创建基准测试。

理想情况

首先,我为理想情况创建了一个基准测试。它一次调用 [n] 个 Promise,其中 n 是物理 CPU 内核的数量。有关完整代码,请参阅 node-swc 仓库 (在新标签页中打开)

const os = require("os");
const cpuCount = os.cpus().length;
 
const SOURCE = `
  // See the link above
`;
 
const SUITES = [
  // ...
  // See the link above
];
 
const arr = [];
for (let i = 0; i < cpuCount / 2; i++) {
  arr.push(0);
}
 
console.info(`CPU Core: ${cpuCount}; Parallelism: ${arr.length}`);
console.info(
  `Note that output of this benchmark should be multiplied by ${arr.length} as this test uses Promise.all`
);
 
SUITES.map(args => {
  const [name, requirePath, fn] = args;
  const func = fn.bind(null, require(requirePath));
  bench(name, async done => {
    await Promise.all(arr.map(v => func()));
    done();
  });
});

我在我的旧台式机上运行了基准测试。它有 E3-v1275 和 24GB 内存。下面的输出是基准测试输出的原样复制。

CPU Core: 8; Parallelism: 4
Note that output of this benchmark should be multiplied by 4 as this test uses Promise.all
[multicore]
swc (es3) x 426 ops/sec ±3.75% (73 runs sampled)
swc (es2015) x 422 ops/sec ±3.57% (74 runs sampled)
swc (es2016) x 987 ops/sec ±2.53% (75 runs sampled)
swc (es2017) x 987 ops/sec ±3.44% (75 runs sampled)
swc (es2018) x 1,221 ops/sec ±2.46% (77 runs sampled)
swc-optimize (es3) x 429 ops/sec ±1.94% (82 runs sampled)
babel (es5) x 6.82 ops/sec ±17.18% (40 runs sampled)

现在,我们需要将其乘以 4,因为我们每次迭代执行 4 个操作。

swc (es3) x 1704 ops/sec ±3.75% (73 runs sampled)
swc (es2015) x 1688 ops/sec ±3.57% (74 runs sampled)
swc (es2016) x 3948 ops/sec ±2.53% (75 runs sampled)
swc (es2017) x 3948 ops/sec ±3.44% (75 runs sampled)
swc (es2018) x 4884 ops/sec ±2.46% (77 runs sampled)
swc-optimize (es3) x 1716 ops/sec ±1.94% (82 runs sampled)
babel (es5) x 27.28 ops/sec ±17.18% (40 runs sampled)

这是实际结果。

babel (es5) 的性能下降了。异步不是免费的。即使 34.05 ops/sec => 27.28 ops/sec 比我预期的要好得多。

多个操作的基准测试

我稍微修改了基准测试文件,使其每次迭代创建 100 个 Promise。

CPU Core: 8; Parallelism: 100
Note that output of this benchmark should be multiplied by 100 as this test uses Promise.all
[multicore]
  swc (es3) x 21.99 ops/sec ±1.83% (54 runs sampled)
  swc (es2015) x 19.11 ops/sec ±3.39% (48 runs sampled)
  swc (es2016) x 55.80 ops/sec ±6.97% (71 runs sampled)
  swc (es2017) x 62.59 ops/sec ±2.12% (74 runs sampled)
  swc (es2018) x 81.08 ops/sec ±5.22% (75 runs sampled)
  swc-optimize (es3) x 18.60 ops/sec ±2.13% (50 runs sampled)
  babel (es5) x 0.32 ops/sec ±19.10% (6 runs sampled)

它必须像上面一样乘以 100。

  swc (es3) x 2199 ops/sec ±1.83% (54 runs sampled)
  swc (es2015) x 1911 ops/sec ±3.39% (48 runs sampled)
  swc (es2016) x 5580 ops/sec ±6.97% (71 runs sampled)
  swc (es2017) x 6259 ops/sec ±2.12% (74 runs sampled)
  swc (es2018) x 8108 ops/sec ±5.22% (75 runs sampled)
  swc-optimize (es3) x 1860 ops/sec ±2.13% (50 runs sampled)
  babel (es5) x 32 ops/sec ±19.10% (6 runs sampled)

为什么 SWC 的性能没有大幅下降?秘密在于 Node.js。Node.js 在内部管理一个工作线程池,SWC 在其中运行。因此,即使你一次创建 100 个 Promise,工作线程的数量也远小于它。

结论

名称1 个核心,同步4 个 Promise100 个 Promise
swc (es3)616 ops/sec1704 ops/sec2199 ops/sec
swc (es2015)677 ops/sec1688 ops/sec1911 ops/sec
swc (es2016)1963 ops/sec3948 op s/sec5580 ops/sec
swc (es2017)1971 ops/sec3948 ops/sec6259 ops/sec
swc (es2018)2555 ops/sec4884 ops/sec8108 ops/sec
swc-optimize (es3)645 ops/sec1716 ops/sec1860 ops/sec
babel (es5)34.05 ops/sec27.28 ops/sec32 ops/sec

swc 扩展良好,因为它几乎所有工作都在工作线程中完成。从 100 个 Promise 的吞吐量比 4 个 Promise 更好的事实可以得出结论,Node.js 的工作线程池利用了超线程。

swc 随着 CPU 内核数量的增加而扩展。 Promise.all 足以进行扩展。