Skip to content

Commit 083b603

Browse files
benchmark testing of shared and per-instance parsers under concurrency
1 parent 31b3977 commit 083b603

File tree

2 files changed

+106
-0
lines changed

2 files changed

+106
-0
lines changed

concurrency-test/bench.js

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import { XMLParser } from "fast-xml-parser";
2+
import { performance } from "node:perf_hooks";
3+
4+
// Generate a bigger XML payload (tune SIZE if needed)
5+
const ITEMS = 50000; // try 5k, 20k, 50k if needed
6+
const xml =
7+
`<root>` +
8+
Array.from({ length: ITEMS }, (_, i) => `<item><id>${i}</id><value>test</value></item>`).join("") +
9+
`</root>`;
10+
11+
function parseWithNewParser() {
12+
const parser = new XMLParser();
13+
return parser.parse(xml);
14+
}
15+
16+
const sharedParser = new XMLParser();
17+
function parseWithSharedParser() {
18+
return sharedParser.parse(xml);
19+
}
20+
21+
async function runScenario({ label, iterations, concurrency, shared }) {
22+
// Create tasks to run in batches of `concurrency`
23+
const parseFn = shared ? parseWithSharedParser : parseWithNewParser;
24+
25+
const t0 = performance.now();
26+
27+
for (let i = 0; i < iterations; i += concurrency) {
28+
const batchSize = Math.min(concurrency, iterations - i);
29+
await Promise.all(
30+
Array.from({ length: batchSize }, () =>
31+
Promise.resolve().then(() => parseFn())
32+
)
33+
);
34+
}
35+
36+
const t1 = performance.now();
37+
return { label, ms: t1 - t0 };
38+
}
39+
40+
function fmt(ms) {
41+
return `${(ms / 1000).toFixed(3)}s`;
42+
}
43+
44+
async function main() {
45+
const rounds = 3; // average a few runs
46+
const iterations = 50; // increase if results are too noisy
47+
const concurrencies = [1, 2, 5, 10, 25, 50];
48+
49+
console.log(`Node: ${process.version}`);
50+
console.log(`ITEMS: ${ITEMS}, iterations: ${iterations}, rounds: ${rounds}\n`);
51+
52+
for (const shared of [true, false]) {
53+
console.log(shared ? "=== Shared parser instance ===" : "=== New parser per task ===");
54+
55+
for (const c of concurrencies) {
56+
const results = [];
57+
for (let r = 0; r < rounds; r++) {
58+
const out = await runScenario({
59+
label: `c=${c}`,
60+
iterations,
61+
concurrency: c,
62+
shared,
63+
});
64+
results.push(out.ms);
65+
}
66+
const avg = results.reduce((a, b) => a + b, 0) / results.length;
67+
console.log(`concurrency ${String(c).padStart(2)} avg: ${fmt(avg)} (runs: ${results.map(fmt).join(", ")})`);
68+
}
69+
console.log("");
70+
}
71+
}
72+
73+
main();

concurrency-test/test.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { XMLParser } from "fast-xml-parser";
2+
3+
const parser = new XMLParser();
4+
5+
const xml = `
6+
<root>
7+
${Array.from({ length: 1000 })
8+
.map((_, i) => `<item><id>${i}</id><value>test</value></item>`)
9+
.join("")}
10+
</root>
11+
`;
12+
13+
function syncParse() {
14+
parser.parse(xml);
15+
}
16+
17+
function asyncParse() {
18+
return Promise.resolve().then(() => parser.parse(xml));
19+
}
20+
21+
async function runTest() {
22+
console.time("sync");
23+
for (let i = 0; i < 1000; i++) syncParse();
24+
console.timeEnd("sync");
25+
26+
console.time("promiseAll");
27+
await Promise.all(
28+
Array.from({ length: 1000 }, () => asyncParse())
29+
);
30+
console.timeEnd("promiseAll");
31+
}
32+
33+
runTest();

0 commit comments

Comments
 (0)