|
1 |
| -# Find Pattern in File - Benchmarks |
| 1 | +<!-- START HEADER --> |
| 2 | +# access-file |
| 3 | +<!-- END HEADER --> |
2 | 4 |
|
3 |
| -This benchmark explores various techniques available in **Node.js** for efficiently finding patterns within a file. |
| 5 | +Description: TBD |
4 | 6 |
|
5 | 7 | ---
|
6 | 8 |
|
7 | 9 | ## Benchmark Requirements
|
8 | 10 |
|
9 |
| -- **Search Content:** The search content should get returned as *string** |
10 |
| - - **Line:** The content should be accessible line by line |
| 11 | +- TBD |
11 | 12 |
|
12 | 13 | ---
|
13 | 14 |
|
14 |
| -## Overview |
| 15 | +<!-- START OVERVIEW --> |
| 16 | +The node:fs.readFileSync benchmark is the fastest. |
15 | 17 |
|
16 |
| -| **File** | **fs.readFileSync** | **fs/promises.readFile** | **readline** | **Fastest Speed Advantage** | |
17 |
| -|-------------------|---------------------|--------------------------|--------------|--------------------------------| |
18 |
| -| `10-loc.txt` | **6.23 µs** | 512.18 µs | 481.15 µs | **77.28x faster** than closest | |
19 |
| -| `100-loc.txt` | **8.08 µs** | 45.42 µs | 459.36 µs | **5.62x faster** than closest | |
20 |
| -| `1000-loc.txt` | **29.52 µs** | 581.85 µs | 781.66 µs | **19.71x faster** than closest | |
21 |
| -| `10000-loc.txt` | **564.30 µs** | 1.22 ms | 2.92 ms | **2.17x faster** than closest | |
22 |
| -| `100000-loc.txt` | 9.32 ms | **8.20 ms** | 14.28 ms | **1.14x faster** than closest | |
23 |
| -| `1000000-loc.txt` | **25.03 ms** | 41.92 ms | 56.63 ms | **1.68x faster** than closest | |
24 | 18 |
|
25 |
| ---- |
26 |
| - |
27 |
| -### How Much Faster? |
| 19 | +## file access; loc: 100; |
28 | 20 |
|
29 |
| -- **Small Files (10-1000 LOC):** |
30 |
| - - `fs.readFileSync` is **5.6x to 77x faster**, showing that synchronous reading is extremely efficient for small |
31 |
| - files. |
| 21 | +| alias | avg (min … max) | p75 | p99 | speed | |
| 22 | +| ------------------------ | ----------------------------------------- | ------------ | ------------ | ------------- | |
| 23 | +| **node:fs.readFileSync** | 7841.36 ns/iter (7640.02 … 8198.60) | 7969.66 ns | 8151.47 ns | 🔥 fastest | |
| 24 | +| node:fs/promise.readFile | 125984.07 ns/iter (99334.00 … 392917.00) | 129583.00 ns | 242250.00 ns | 16.07x slower | |
| 25 | +| node:readline | 232471.74 ns/iter (192542.00 … 556833.00) | 240958.00 ns | 329459.00 ns | 29.65x slower | |
32 | 26 |
|
33 |
| -- **Medium Files (10,000 LOC):** |
34 |
| - - The speed difference reduces, but `fs.readFileSync` remains **2.17x faster** than its async counterpart. |
| 27 | +## file access; loc: 1000; |
35 | 28 |
|
36 |
| -- **Large Files (100,000 LOC):** |
37 |
| - - Surprisingly, `fs/promises.readFile` slightly outperforms `fs.readFileSync`, indicating that asynchronous |
38 |
| - operations can start to optimize better for larger file sizes. |
| 29 | +| alias | avg (min … max) | p75 | p99 | speed | |
| 30 | +| ------------------------ | ----------------------------------------- | ------------ | ------------ | ------------- | |
| 31 | +| **node:fs.readFileSync** | 26773.27 ns/iter (26543.04 … 27086.21) | 26905.63 ns | 26973.61 ns | 🔥 fastest | |
| 32 | +| node:fs/promise.readFile | 70881.15 ns/iter (59850.19 … 73539.74) | 73092.68 ns | 73466.15 ns | 2.65x slower | |
| 33 | +| node:readline | 646319.26 ns/iter (572083.00 … 770583.00) | 662459.00 ns | 744791.00 ns | 24.14x slower | |
39 | 34 |
|
40 |
| -- **Massive Files (1,000,000 LOC):** |
41 |
| - - `fs.readFileSync` regains performance advantage, being **1.68x faster** than the async variant, and **2.26x faster |
42 |
| - ** than `readline`. |
| 35 | +## file access; loc: 10000; |
43 | 36 |
|
44 |
| ---- |
| 37 | +| alias | avg (min … max) | p75 | p99 | speed | |
| 38 | +| ---------------------------- | -------------------------------------------- | ------------- | ------------- | ------------- | |
| 39 | +| **node:fs/promise.readFile** | 376297.66 ns/iter (338625.00 … 504542.00) | 383958.00 ns | 452875.00 ns | 🔥 fastest | |
| 40 | +| node:fs.readFileSync | 533772.21 ns/iter (478959.00 … 741250.00) | 543834.00 ns | 684750.00 ns | 1.42x slower | |
| 41 | +| node:readline | 4402708.96 ns/iter (3836916.00 … 4858125.00) | 4534834.00 ns | 4808333.00 ns | 11.70x slower | |
45 | 42 |
|
46 |
| -## File Content Access Methods |
47 |
| - |
48 |
| ---- |
| 43 | +## file access; loc: 100000; |
49 | 44 |
|
50 |
| -Overview |
| 45 | +| alias | avg (min … max) | p75 | p99 | speed | |
| 46 | +| ---------------------------- | ----------------------------------------------- | -------------- | -------------- | ------------- | |
| 47 | +| **node:fs/promise.readFile** | 2691327.25 ns/iter (2555917.00 … 3081917.00) | 2728375.00 ns | 3069541.00 ns | 🔥 fastest | |
| 48 | +| node:fs.readFileSync | 4212338.30 ns/iter (4005833.00 … 4749417.00) | 4285792.00 ns | 4608083.00 ns | 1.57x slower | |
| 49 | +| node:readline | 37398813.81 ns/iter (36849334.00 … 38135625.00) | 37536625.00 ns | 37965208.00 ns | 13.90x slower | |
51 | 50 |
|
52 |
| -- `node:fs.readFileSync` |
53 |
| -- `node:fs.readFile` |
54 |
| -- `node:fs.createReadStream` with `node:readline.createInterface` |
| 51 | +<!-- END OVERVIEW --> |
55 | 52 |
|
56 | 53 | ---
|
57 | 54 |
|
58 |
| -### 1. Synchronous File Reading |
59 |
| - |
60 |
| -- **Method:** `fs.readFileSync` |
61 |
| -- **Description:** Reads the entire file synchronously into memory before processing. |
62 |
| -- **Source:** [node-fs.readFileSync.ts](./src/node-fs.readFileSync.ts) |
63 |
| - |
64 |
| -```javascript |
65 |
| -import * as fs from "node:fs"; |
| 55 | +<!-- START CASES --> |
| 56 | +## node-fs.promise.readFile.ts |
| 57 | +_[node-fs.promise.readFile.ts](access-file/src)_ |
| 58 | +```ts |
| 59 | +import * as fs from "node:fs/promises"; |
66 | 60 |
|
67 |
| -export default function accessContent(filePath: string): void { |
68 |
| - const content = fs.readFileSync(filePath, "utf8"); |
69 |
| - content.split("\n") |
70 |
| - .forEach(line => (line === 'not-in-file')); |
| 61 | +export default function accessFile(filePath: string): Promise<string> { |
| 62 | + return fs.readFile(filePath, "utf8"); |
71 | 63 | }
|
72 |
| -``` |
73 |
| - |
74 |
| -### 2. Asynchronous File Reading |
75 | 64 |
|
76 |
| -- **Method:** `fs.promises.readFile` |
77 |
| -- **Description:** Reads the entire file asynchronously into memory before processing. |
78 |
| -- **Source:** [node-fs.promise.readFile.ts](./src/node-fs.promise.readFile.ts) |
| 65 | +``` |
79 | 66 |
|
80 |
| -```javascript |
81 |
| -import * as fs from "node:fs/promises"; |
| 67 | +## node-fs.readFileSync.ts |
| 68 | +_[node-fs.readFileSync.ts](access-file/src)_ |
| 69 | +```ts |
| 70 | +import * as fs from "node:fs"; |
82 | 71 |
|
83 |
| -export default async function accessContent(filePath): Promise<void> { |
84 |
| - const content = await fs.readFile(filePath, "utf8"); |
85 |
| - content.split("\n") |
86 |
| - .forEach(line => (line === 'not-in-file')); |
| 72 | +export default function accessFile(filePath: string): string { |
| 73 | + return fs.readFileSync(filePath, "utf8"); |
87 | 74 | }
|
88 |
| -``` |
89 | 75 |
|
90 |
| -### 3. Streaming File Reading (Line by Line) |
91 |
| - |
92 |
| -- **Method:** `fs.createReadStream` with `readline.createInterface` |
93 |
| -- **Description:** Processes the file line by line without loading the entire file into memory. |
94 |
| -- **Source:** [node-readline](./src/node-readline.ts) |
| 76 | +``` |
95 | 77 |
|
96 |
| -```javascript |
| 78 | +## node-readline.ts |
| 79 | +_[node-readline.ts](access-file/src)_ |
| 80 | +```ts |
97 | 81 | import * as fs from "node:fs";
|
98 | 82 | import * as readline from "node:readline";
|
99 | 83 |
|
100 |
| -export default async function accessContent(filePath: string): Promise<void> { |
| 84 | +export default async function* accessFile(filePath: string): AsyncGenerator<string> { |
101 | 85 | const stream = fs.createReadStream(filePath);
|
102 | 86 | const rl = readline.createInterface({input: stream});
|
103 |
| - for await (const line of rl) { |
104 |
| - line === 'not-in-file'; |
| 87 | + |
| 88 | + try { |
| 89 | + for await (const line of rl) { |
| 90 | + yield line; |
| 91 | + } |
| 92 | + } finally { |
| 93 | + rl.close(); |
105 | 94 | }
|
106 | 95 | }
|
| 96 | + |
107 | 97 | ```
|
108 | 98 |
|
| 99 | +<!-- END CASES --> |
| 100 | + |
109 | 101 | ---
|
110 | 102 |
|
111 | 103 | ## Benchmark Results
|
112 | 104 |
|
113 |
| -```shell |
114 |
| -> npx tsx --tsconfig=../tsconfig.perf.json file-access |
115 |
| - |
| 105 | +<!-- START DATA --> |
| 106 | +```bash |
116 | 107 | clk: ~3.33 GHz
|
117 | 108 | cpu: Apple M2 Max
|
118 |
| -runtime: node 22.12.0 (arm64-darwin) |
| 109 | +runtime: node 23.9.0 (arm64-darwin) |
119 | 110 |
|
120 | 111 | benchmark avg (min … max) p75 / p99 (min … top 1%)
|
121 | 112 | ------------------------------------------- -------------------------------
|
122 |
| -• file access; loc: 10; |
123 |
| -------------------------------------------- ------------------------------- |
124 |
| -node:fs.readFileSync 6.23 µs/iter 6.26 µs 6.83 µs ▂█▆▃▂▁▁▁▁▁▁ |
125 |
| -node:fs/promise.readFile 512.18 µs/iter 661.42 µs 1.36 ms ▂█▄▂▃▂▁▁▁▁▁ |
126 |
| -node:readline 481.15 µs/iter 533.42 µs 978.21 µs ▁▁▂█▅▂▂▂▂▁▁ |
127 |
| - |
128 |
| -summary |
129 |
| - node:fs.readFileSync |
130 |
| - 77.28x faster than node:readline |
131 |
| - 82.26x faster than node:fs/promise.readFile |
132 |
| - |
133 | 113 | • file access; loc: 100;
|
134 | 114 | ------------------------------------------- -------------------------------
|
135 |
| -node:fs.readFileSync 8.08 µs/iter 8.09 µs 8.38 µs ▃▅▇█▅▃▁▁▃▃▂ |
136 |
| -node:fs/promise.readFile 45.42 µs/iter 45.30 µs 46.21 µs ▅▃█▅▁▁▁▁▃▁▃ |
137 |
| -node:readline 459.36 µs/iter 515.54 µs 931.92 µs ▁▁▂█▅▂▂▂▂▁▁ |
| 115 | +node:fs.readFileSync 7.93 µs/iter 7.98 µs 8.13 µs ▃▇▄▇▆█▂▁▁▂▂ |
| 116 | +node:fs/promise.readFile 124.55 µs/iter 130.13 µs 201.29 µs ▃▅█▇▃▂▁▁▁▁▁ |
| 117 | +node:readline 233.24 µs/iter 241.75 µs 341.08 µs ▁███▄▂▂▁▁▁▁ |
138 | 118 |
|
139 | 119 | summary
|
140 | 120 | node:fs.readFileSync
|
141 |
| - 5.62x faster than node:fs/promise.readFile |
142 |
| - 56.83x faster than node:readline |
| 121 | + 15.71x faster than node:fs/promise.readFile |
| 122 | + 29.42x faster than node:readline |
143 | 123 |
|
144 | 124 | • file access; loc: 1000;
|
145 | 125 | ------------------------------------------- -------------------------------
|
146 |
| -node:fs.readFileSync 29.52 µs/iter 29.07 µs 29.82 µs ▂▂█▁▄▂▁▁▁▁▂ |
147 |
| -node:fs/promise.readFile 581.85 µs/iter 720.67 µs 1.35 ms ▁▇█▂▂▃▂▂▁▁▁ |
148 |
| -node:readline 781.66 µs/iter 837.54 µs 1.36 ms ▁▁▁▄█▃▂▂▂▂▁ |
| 126 | +node:fs.readFileSync 27.72 µs/iter 27.87 µs 28.31 µs ▅▅█▅▅▁▅▁▁▁▅ |
| 127 | +node:fs/promise.readFile 71.42 µs/iter 73.95 µs 74.04 µs ▃▁▁▁▁▁▁▁▁▅█ |
| 128 | +node:readline 644.37 µs/iter 662.00 µs 743.96 µs ▁▁▃▅██▅▃▂▁▁ |
149 | 129 |
|
150 | 130 | summary
|
151 | 131 | node:fs.readFileSync
|
152 |
| - 19.71x faster than node:fs/promise.readFile |
153 |
| - 26.48x faster than node:readline |
| 132 | + 2.58x faster than node:fs/promise.readFile |
| 133 | + 23.24x faster than node:readline |
154 | 134 |
|
155 | 135 | • file access; loc: 10000;
|
156 | 136 | ------------------------------------------- -------------------------------
|
157 |
| -node:fs.readFileSync 564.30 µs/iter 568.13 µs 1.44 ms ▂▁█▃▁▁▁▁▁▁▁ |
158 |
| -node:fs/promise.readFile 1.22 ms/iter 1.38 ms 1.74 ms ▁▅█▇▆▆▇▄▃▂▁ |
159 |
| -node:readline 2.92 ms/iter 3.00 ms 3.23 ms ▁▃▅▄▆█▇▅▃▂▁ |
| 137 | +node:fs.readFileSync 566.27 µs/iter 576.13 µs 757.79 µs ▂██▄▂▂▂▂▁▁▁ |
| 138 | +node:fs/promise.readFile 381.38 µs/iter 389.38 µs 491.50 µs ▂▄██▄▂▁▁▁▁▁ |
| 139 | +node:readline 4.48 ms/iter 4.64 ms 4.94 ms ▁▃▃▃▅▇█▇▃▃▁ |
160 | 140 |
|
161 | 141 | summary
|
162 |
| - node:fs.readFileSync |
163 |
| - 2.17x faster than node:fs/promise.readFile |
164 |
| - 5.17x faster than node:readline |
| 142 | + node:fs/promise.readFile |
| 143 | + 1.48x faster than node:fs.readFileSync |
| 144 | + 11.75x faster than node:readline |
165 | 145 |
|
166 | 146 | • file access; loc: 100000;
|
167 | 147 | ------------------------------------------- -------------------------------
|
168 |
| -node:fs.readFileSync 9.32 ms/iter 9.65 ms 9.97 ms ▁▁▁▁▁▁▁▂▄█▂ |
169 |
| -node:fs/promise.readFile 8.20 ms/iter 8.78 ms 9.28 ms ▃▄▂▂▃▃▄▆█▄▁ |
170 |
| -node:readline 14.28 ms/iter 14.46 ms 15.08 ms ▂▆█▆▅▃▄▂▂▂▂ |
| 148 | +node:fs.readFileSync 4.48 ms/iter 4.59 ms 5.82 ms ▂█▅▄▂▁▂▁▂▁▁ |
| 149 | +node:fs/promise.readFile 2.78 ms/iter 2.82 ms 3.45 ms ▃▇█▅▃▁▂▂▂▂▁ |
| 150 | +node:readline 39.24 ms/iter 39.38 ms 42.57 ms ▂▅█▄▂▂▂▁▂▁▂ |
171 | 151 |
|
172 | 152 | summary
|
173 | 153 | node:fs/promise.readFile
|
174 |
| - 1.14x faster than node:fs.readFileSync |
175 |
| - 1.74x faster than node:readline |
176 |
| - |
177 |
| -• file access; loc: 1000000; |
178 |
| -------------------------------------------- ------------------------------- |
179 |
| -node:fs.readFileSync 25.03 ms/iter 24.87 ms 34.75 ms ▂█▂▁▁▁▁▁▁▁▁ |
180 |
| -node:fs/promise.readFile 41.92 ms/iter 45.11 ms 46.60 ms ▅▄▁▁▁▃▃▄█▇▃ |
181 |
| -node:readline 56.63 ms/iter 56.98 ms 57.20 ms ▃▁▃▃▆▆▅▆▃█▃ |
| 154 | + 1.61x faster than node:fs.readFileSync |
| 155 | + 14.13x faster than node:readline |
182 | 156 |
|
183 |
| -summary |
184 |
| - node:fs.readFileSync |
185 |
| - 1.68x faster than node:fs/promise.readFile |
186 |
| - 2.26x faster than node:readline |
187 | 157 | ```
|
| 158 | + |
| 159 | +<!-- END DATA --> |
0 commit comments