-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
esbuild wasm vs binary #219
Comments
Yes. The WebAssembly version has consistently been ~10x slower than the binary version in my testing, for both the
I'm also not sure how much effort has gone into the WebAssembly backend but it could potentially also have not received as much optimization work as the other native backends. I really should add the WebAssembly version to my performance benchmarks because this question keeps coming up. |
Thanks for the explanation, I forgot that WASM doesn't allow multi threading yet. I only use the single file transform, I wonder if it still creates multiple threads if I transform multiple files in parallel from JS. For either the Go or WASM implementation. |
The Go code uses one goroutine for each API call, so each API call should be on a separate thread in the native implementation. The WebAssembly implementation still uses multiple goroutines but only has one thread available, so the API calls are still all run on a single thread. Here's the benchmark code I made for this issue: const fs = require('fs')
const code = fs.readFileSync('./node_modules/esbuild-wasm/lib/browser.js', 'utf8')
async function benchmark(esbuild) {
const service = await esbuild.startService()
for (let i = 0; i < 10; i++) await service.transform(code, {})
await new Promise(r => setTimeout(r, 250))
let start = Date.now()
let promises = []
for (let i = 0; i < 1000; i++) promises.push(service.transform(code, {}))
await Promise.all(promises)
let time = Date.now() - start
service.stop()
return time
}
async function main() {
let native = await benchmark(require('esbuild'))
console.log(`native: ${native}ms`)
let wasm = await benchmark(require('esbuild-wasm'))
console.log(`wasm: ${wasm}ms`)
console.log(`native is ${(wasm / native).toFixed(1)}x faster than wasm`)
}
main().catch(e => setTimeout(() => { throw e })) It even does some warmup API calls before running the benchmark to give node's WebAssembly JIT some time to do its thing, so this should be a fair comparison. Here's what I get when I run this:
|
Similar results here on my macbook pro:
I think I will see if the postinstall is giving people any issues, maybe allow opting into the wasm implementation with a flag instead. |
That approach sounds reasonable. Please let me know if people encounter postinstall issues. Another interesting data point: you can remove the multi-threading advantage of native by prefixing the benchmark command with
|
I'm going to close this since this is a question, not an issue with esbuild, and I believe that this discussion accurately answers the question. |
Thanks a lot for esbuild. Im going to ship esbuild as part of the test runner and dev server at https://github.com/modernweb-dev/web. One thing in still wondering about is whether to use the esbuild wasm build or the binary.
The docs mention wasm as a fallback, but it seems to me like its the most reliable option to use for a node based project. The postinstall script for the binary build could be problematic for people, and may not work in a CI or restricted environments. What do you think about this? Are there any performance differences to consider?
The text was updated successfully, but these errors were encountered: