Skip to content

Deno

This page summarizes Deno benchmark runs for Knitting on deno 2.6.6 (aarch64-apple-darwin).

This benchmark compares one round-trip between a main thread and workers using different transports. Knitting keeps the lowest overhead in this setup:

  • 1 message: Knitting is about 3.5x faster than worker postMessage, 3.6x faster than websocket, and 10x faster than HTTP.
  • 25 messages: Knitting is about 9.5x faster than worker postMessage.
  • 50 messages: Knitting is about 10.7x faster than worker postMessage.
Deno IPC benchmark

These charts compare the same payload families sent through Knitting and Deno workers.

With a single value per call, Knitting is consistently faster:

  • For small primitives, Knitting is roughly 25-30x faster than workers.
  • For string/array/object payloads, Knitting is usually around 4-6x faster.
  • For larger payloads, Knitting still holds a clear advantage (for example, big object: 6.37 µs vs 27.45 µs, about 4.3x faster).
Deno knitting vs worker benchmark 1

At 100 messages per iteration, the gap remains strong:

  • Typical primitives stay around 18-35x faster with Knitting.
  • Heavier payloads still keep a clear edge at roughly ~7x faster.
  • Batching improves throughput for both, but Knitting remains lower-overhead across payload classes.
Deno knitting vs worker benchmark 100

This benchmark increases payload size from 32 B up to 1,048,576 B (1 MiB) and reports batched cost with batch=64.

Using the 1048576 B row (avg) from the batch=64 run, one-way transfer throughput is:

  • string: 19.89 ms/iter -> 3.37 GB/s
  • Uint8Array: 11.61 ms/iter -> 5.78 GB/s

Interpretation:

  • Deno stays in the middle of the pack under batching, with binary ahead of string in this run.
  • For 1 MiB Uint8Array, throughput lands around ~5.8 GB/s; string is closer to ~3.4 GB/s.
deno_call-growth-batch.md
clk: ~3.61 GHz
cpu: Apple M3 Ultra
runtime: deno 2.6.6 (aarch64-apple-darwin)
| • call growth batch string (ascii 32..1048576 x4, batch=64) | avg | min | p75 | p99 | max |
| --------- | ---------------- | ----------- | ----------- | ----------- | ----------- |
| 32 B | ` 30.31 µs/iter` | ` 16.42 µs` | ` 39.71 µs` | ` 77.08 µs` | `302.17 µs` |
| 128 B | ` 30.07 µs/iter` | ` 26.71 µs` | ` 30.92 µs` | ` 33.21 µs` | ` 33.46 µs` |
| 512 B | ` 31.72 µs/iter` | ` 28.87 µs` | ` 32.66 µs` | ` 32.95 µs` | ` 32.95 µs` |
| 2048 B | `110.51 µs/iter` | ` 57.67 µs` | `120.29 µs` | `187.04 µs` | `960.67 µs` |
| 8192 B | `154.78 µs/iter` | ` 80.58 µs` | `173.04 µs` | `254.96 µs` | `316.83 µs` |
| 32768 B | `292.53 µs/iter` | `227.79 µs` | `312.42 µs` | `423.71 µs` | `500.46 µs` |
| 131072 B | ` 4.18 ms/iter` | ` 2.47 ms` | ` 5.65 ms` | ` 8.42 ms` | ` 9.31 ms` |
| 524288 B | ` 11.47 ms/iter` | ` 9.01 ms` | ` 11.40 ms` | ` 14.34 ms` | ` 15.34 ms` |
| 1048576 B | ` 19.89 ms/iter` | ` 17.47 ms` | ` 20.50 ms` | ` 23.38 ms` | ` 25.33 ms` |
| • call growth batch uint8array (32..1048576 x4, batch=64) | avg | min | p75 | p99 | max |
| --------- | ---------------- | ----------- | ----------- | ----------- | ----------- |
| 32 B | ` 27.44 µs/iter` | ` 17.92 µs` | ` 31.54 µs` | ` 63.96 µs` | `224.21 µs` |
| 128 B | ` 27.83 µs/iter` | ` 25.18 µs` | ` 28.79 µs` | ` 29.28 µs` | ` 29.52 µs` |
| 512 B | ` 31.88 µs/iter` | ` 30.56 µs` | ` 32.45 µs` | ` 33.35 µs` | ` 35.16 µs` |
| 2048 B | `121.18 µs/iter` | ` 51.75 µs` | `132.00 µs` | `213.21 µs` | ` 2.91 ms` |
| 8192 B | `230.85 µs/iter` | `112.54 µs` | `219.79 µs` | ` 1.66 ms` | ` 3.09 ms` |
| 32768 B | `527.39 µs/iter` | `241.25 µs` | `457.08 µs` | ` 2.48 ms` | ` 3.33 ms` |
| 131072 B | ` 1.79 ms/iter` | ` 1.04 ms` | ` 1.91 ms` | ` 4.85 ms` | ` 5.29 ms` |
| 524288 B | ` 6.32 ms/iter` | ` 4.51 ms` | ` 7.14 ms` | ` 8.85 ms` | ` 10.38 ms` |
| 1048576 B | ` 11.61 ms/iter` | ` 9.68 ms` | ` 12.61 ms` | ` 14.15 ms` | ` 14.24 ms` |

This stress test computes prime numbers over a large range, then serializes and parses large JSON payloads:

const N = 10_000_000; // search range: [1..N]
const CHUNK_SIZE = 250_000;

Even under this heavier workload, parallel workers scale well:

  • main + 1 extra thread: ~1.8x faster than main only.
  • main + 2 extra threads: ~2.5x faster than main only.
  • main + 3 extra threads: ~3.2x faster than main only.
  • main + 4 extra threads: ~3.7x faster than main only.
deno_withload.md
clk: ~3.61 GHz
cpu: Apple M3 Ultra
runtime: deno 2.6.6 (aarch64-apple-darwin)
| • knitting: primes up to 10,000,000 (chunk=250,000) | avg | min | p75 | p99 | max |
| ----------------------------------- | ---------------- | ----------- | ----------- | ----------- | ----------- |
| main | `956.62 ms/iter` | `950.73 ms` | `957.55 ms` | `959.96 ms` | `963.62 ms` |
| main + 1 extra threads → full range | `496.69 ms/iter` | `492.92 ms` | `497.48 ms` | `501.54 ms` | `501.70 ms` |
| main + 2 extra threads → full range | `360.28 ms/iter` | `355.94 ms` | `361.84 ms` | `364.48 ms` | `366.29 ms` |
| main + 3 extra threads → full range | `292.60 ms/iter` | `288.34 ms` | `293.62 ms` | `296.29 ms` | `300.23 ms` |
| main + 4 extra threads → full range | `254.74 ms/iter` | `251.74 ms` | `256.04 ms` | `256.66 ms` | `258.82 ms` |

This benchmark covers primitive, structured, collection, typed-array, error/date/symbol, promise-arg, and static-vs-dynamic allocator paths. Results are reported for count 1 and count 100 to show both per-call latency and batched throughput.

Quick takeaways:

  • In count 100, primitive-style payloads are usually in the ~20-50 µs range, while heavier structured/collection payloads can be ~160 µs to multi-millisecond outliers.
  • The static payload path is usually around ~1.8x-2.5x faster than dynamic allocator paths (for example: string ~2.2x, json ~2.5x, Uint8Array ~1.8x, symbol ~2.2x at count 100).

Payload sizes (approximate):

PayloadSize
jsonObj206 B
jsonArr217 B
mapPayload284 B
Uint8Array1024 B
Int32Array1024 B
Float64Array1024 B
BigInt64Array1024 B
BigUint64Array1024 B
DataView1024 B
smallU8480 B
largeU8481 B
deno_types_knitting.md
payload sizes (approx bytes):
jsonObj: 206 bytes
jsonArr: 217 bytes
stringHuge: 1024 bytes
Uint8Array: 1024 bytes
Int32Array: 1024 bytes
Float64Array: 1024 bytes
BigInt64Array: 1024 bytes
BigUint64Array: 1024 bytes
DataView: 1024 bytes
clk: ~3.61 GHz
cpu: Apple M3 Ultra
runtime: deno 2.6.6 (aarch64-apple-darwin)
| • knitting-types 1 | avg | min | p75 | p99 | max |
| --------------------- | ---------------- | ----------- | ----------- | ----------- | ----------- |
| number -> (1) | ` 1.25 µs/iter` | `500.00 ns` | `667.00 ns` | ` 8.33 µs` | `159.96 µs` |
| bigint small -> (1) | ` 1.35 µs/iter` | `500.00 ns` | `667.00 ns` | ` 8.42 µs` | `151.29 µs` |
| bigint large -> (1) | ` 6.53 µs/iter` | ` 1.42 µs` | ` 6.25 µs` | ` 25.58 µs` | `154.50 µs` |
| boolean true -> (1) | `915.37 ns/iter` | `513.63 ns` | ` 1.08 µs` | ` 2.64 µs` | ` 2.92 µs` |
| boolean false -> (1) | `946.00 ns/iter` | `505.40 ns` | ` 1.21 µs` | ` 2.69 µs` | ` 3.18 µs` |
| undefined -> (1) | `978.82 ns/iter` | `517.35 ns` | ` 1.28 µs` | ` 2.72 µs` | ` 3.46 µs` |
| null -> (1) | `766.20 ns/iter` | `513.38 ns` | `700.95 ns` | ` 2.26 µs` | ` 2.50 µs` |
| string -> (1) | ` 4.39 µs/iter` | ` 3.27 µs` | ` 4.73 µs` | ` 5.35 µs` | ` 5.58 µs` |
| json object -> (1) | ` 6.90 µs/iter` | ` 6.81 µs` | ` 6.95 µs` | ` 6.99 µs` | ` 7.08 µs` |
| json array -> (1) | ` 6.91 µs/iter` | ` 6.80 µs` | ` 6.94 µs` | ` 6.98 µs` | ` 7.04 µs` |
| Uint8Array -> (1) | ` 7.04 µs/iter` | ` 1.42 µs` | ` 6.83 µs` | ` 25.00 µs` | `144.58 µs` |
| ArrayBuffer -> (1) | ` 6.79 µs/iter` | ` 6.58 µs` | ` 6.87 µs` | ` 7.16 µs` | ` 7.58 µs` |
| Buffer -> (1) | ` 6.50 µs/iter` | ` 6.39 µs` | ` 6.55 µs` | ` 6.66 µs` | ` 6.72 µs` |
| string huge -> (1) | ` 6.40 µs/iter` | ` 6.24 µs` | ` 6.47 µs` | ` 6.53 µs` | ` 6.54 µs` |
| Int32Array -> (1) | ` 6.54 µs/iter` | ` 6.38 µs` | ` 6.58 µs` | ` 6.84 µs` | ` 6.86 µs` |
| Float64Array -> (1) | ` 6.47 µs/iter` | ` 6.29 µs` | ` 6.54 µs` | ` 6.65 µs` | ` 6.69 µs` |
| BigInt64Array -> (1) | ` 6.60 µs/iter` | ` 6.41 µs` | ` 6.66 µs` | ` 6.80 µs` | ` 6.86 µs` |
| BigUint64Array -> (1) | ` 6.59 µs/iter` | ` 6.38 µs` | ` 6.68 µs` | ` 6.83 µs` | ` 6.89 µs` |
| DataView -> (1) | ` 6.61 µs/iter` | ` 6.47 µs` | ` 6.69 µs` | ` 6.78 µs` | ` 6.82 µs` |
| Date -> (1) | ` 4.17 µs/iter` | ` 3.22 µs` | ` 4.48 µs` | ` 4.77 µs` | ` 4.95 µs` |
| Symbol.for -> (1) | ` 4.45 µs/iter` | ` 3.74 µs` | ` 4.75 µs` | ` 5.05 µs` | ` 5.09 µs` |
| • knitting-types 100 | avg | min | p75 | p99 | max |
| ----------------------- | ---------------- | ----------- | ----------- | ----------- | ----------- |
| number -> (100) | ` 24.18 µs/iter` | ` 14.88 µs` | ` 32.96 µs` | ` 60.75 µs` | `215.58 µs` |
| bigint small -> (100) | ` 24.50 µs/iter` | ` 22.23 µs` | ` 25.18 µs` | ` 26.85 µs` | ` 28.16 µs` |
| bigint large -> (100) | ` 73.66 µs/iter` | ` 53.08 µs` | ` 75.79 µs` | `145.08 µs` | `236.29 µs` |
| boolean true -> (100) | ` 25.91 µs/iter` | ` 22.28 µs` | ` 27.88 µs` | ` 29.93 µs` | ` 30.14 µs` |
| boolean false -> (100) | ` 25.54 µs/iter` | ` 22.95 µs` | ` 26.74 µs` | ` 27.98 µs` | ` 28.97 µs` |
| undefined -> (100) | ` 25.79 µs/iter` | ` 22.26 µs` | ` 27.06 µs` | ` 28.38 µs` | ` 32.01 µs` |
| null -> (100) | ` 25.27 µs/iter` | ` 22.40 µs` | ` 26.41 µs` | ` 28.21 µs` | ` 29.08 µs` |
| string -> (100) | ` 33.66 µs/iter` | ` 31.45 µs` | ` 34.56 µs` | ` 35.26 µs` | ` 36.58 µs` |
| json object -> (100) | `113.57 µs/iter` | ` 98.63 µs` | `114.63 µs` | `207.79 µs` | `311.75 µs` |
| json array -> (100) | `146.72 µs/iter` | `119.58 µs` | `154.08 µs` | `257.83 µs` | `472.75 µs` |
| Uint8Array -> (100) | `225.34 µs/iter` | `114.58 µs` | `238.04 µs` | `343.42 µs` | ` 2.87 ms` |
| ArrayBuffer -> (100) | `235.43 µs/iter` | `122.13 µs` | `252.79 µs` | `343.42 µs` | ` 2.11 ms` |
| Buffer -> (100) | `223.72 µs/iter` | `116.79 µs` | `236.96 µs` | `333.08 µs` | ` 2.81 ms` |
| string huge -> (100) | `208.01 µs/iter` | `101.08 µs` | `221.21 µs` | `312.46 µs` | `412.83 µs` |
| Int32Array -> (100) | `231.01 µs/iter` | ` 99.58 µs` | `240.63 µs` | `360.17 µs` | ` 2.84 ms` |
| Float64Array -> (100) | `228.32 µs/iter` | `113.75 µs` | `240.58 µs` | `356.08 µs` | ` 2.99 ms` |
| BigInt64Array -> (100) | `236.59 µs/iter` | `116.83 µs` | `244.21 µs` | `377.42 µs` | ` 2.82 ms` |
| BigUint64Array -> (100) | `228.29 µs/iter` | `121.71 µs` | `240.17 µs` | `350.04 µs` | ` 2.78 ms` |
| DataView -> (100) | `229.76 µs/iter` | `120.04 µs` | `240.04 µs` | `330.33 µs` | ` 2.77 ms` |
| Date -> (100) | ` 33.88 µs/iter` | ` 31.90 µs` | ` 35.10 µs` | ` 36.25 µs` | ` 37.30 µs` |
| Symbol.for -> (100) | ` 37.24 µs/iter` | ` 35.52 µs` | ` 37.89 µs` | ` 38.57 µs` | ` 39.37 µs` |
| • knitting-promise-args 1 | avg | min | p75 | p99 | max |
| --------------------- | ---------------- | ----------- | ----------- | ----------- | ----------- |
| promise number -> (1) | ` 5.82 µs/iter` | ` 5.61 µs` | ` 5.88 µs` | ` 6.22 µs` | ` 6.56 µs` |
| promise object -> (1) | ` 6.83 µs/iter` | ` 6.60 µs` | ` 6.93 µs` | ` 7.11 µs` | ` 7.31 µs` |
| • knitting-promise-args 100 | avg | min | p75 | p99 | max |
| ----------------------- | ---------------- | ----------- | ----------- | ----------- | ----------- |
| promise number -> (100) | ` 47.74 µs/iter` | ` 45.95 µs` | ` 48.23 µs` | ` 48.55 µs` | ` 49.80 µs` |
| promise object -> (100) | ` 89.87 µs/iter` | ` 64.33 µs` | ` 96.21 µs` | `194.17 µs` | `345.00 µs` |