sabcom 0.1.95 → 0.1.123
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +94 -0
- package/package.json +10 -10
package/README.md
CHANGED
|
@@ -140,6 +140,100 @@ await write(data, buffer, {
|
|
|
140
140
|
* **Smaller Buffer**: Less memory usage, more context switches/atomic operations.
|
|
141
141
|
* **Recommendation**: Start with 4KB - 64KB (`4096` - `65536`) depending on your average payload size.
|
|
142
142
|
|
|
143
|
+
## Multi-Worker Architecture
|
|
144
|
+
|
|
145
|
+
When multiple workers need to communicate with the main thread simultaneously, create a separate `SharedArrayBuffer` for each worker. Each buffer is an independent communication channel.
|
|
146
|
+
|
|
147
|
+
**main.ts**
|
|
148
|
+
```typescript
|
|
149
|
+
import { Worker } from 'worker_threads';
|
|
150
|
+
import { write, read } from 'sabcom';
|
|
151
|
+
|
|
152
|
+
interface WorkerChannel {
|
|
153
|
+
worker: Worker;
|
|
154
|
+
buffer: SharedArrayBuffer;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
async function createWorker(id: number): Promise<WorkerChannel> {
|
|
158
|
+
const buffer = new SharedArrayBuffer(4096);
|
|
159
|
+
const worker = new Worker('./worker.js', {
|
|
160
|
+
workerData: { id, buffer }
|
|
161
|
+
});
|
|
162
|
+
return { worker, buffer };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
async function main() {
|
|
166
|
+
// Create multiple workers, each with its own buffer
|
|
167
|
+
const channels: WorkerChannel[] = await Promise.all([
|
|
168
|
+
createWorker(0),
|
|
169
|
+
createWorker(1),
|
|
170
|
+
createWorker(2),
|
|
171
|
+
]);
|
|
172
|
+
|
|
173
|
+
// Send data to all workers in parallel
|
|
174
|
+
const tasks = ['task-a', 'task-b', 'task-c'];
|
|
175
|
+
await Promise.all(
|
|
176
|
+
channels.map((ch, i) =>
|
|
177
|
+
write(new TextEncoder().encode(tasks[i]), ch.buffer)
|
|
178
|
+
)
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
// Read responses from all workers in parallel
|
|
182
|
+
const responses = await Promise.all(
|
|
183
|
+
channels.map(ch => read(ch.buffer))
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
responses.forEach((data, i) => {
|
|
187
|
+
console.log(`Worker ${i}: ${new TextDecoder().decode(data)}`);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
// Cleanup
|
|
191
|
+
await Promise.all(channels.map(ch => ch.worker.terminate()));
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
main();
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
**worker.ts**
|
|
198
|
+
```typescript
|
|
199
|
+
import { workerData, parentPort } from 'worker_threads';
|
|
200
|
+
import { readSync, writeSync } from 'sabcom';
|
|
201
|
+
|
|
202
|
+
const { id, buffer } = workerData as { id: number; buffer: SharedArrayBuffer };
|
|
203
|
+
|
|
204
|
+
// Receive task from main
|
|
205
|
+
const task = new TextDecoder().decode(readSync(buffer));
|
|
206
|
+
console.log(`Worker ${id} received: ${task}`);
|
|
207
|
+
|
|
208
|
+
// Process and respond
|
|
209
|
+
const result = `${task.toUpperCase()}-done`;
|
|
210
|
+
writeSync(new TextEncoder().encode(result), buffer);
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Key Points for Multi-Worker Setup
|
|
214
|
+
|
|
215
|
+
1. **One buffer per worker** - Each worker needs its own `SharedArrayBuffer`. A single buffer can only handle one reader-writer pair at a time.
|
|
216
|
+
|
|
217
|
+
2. **Buffer ownership** - Each buffer represents a bidirectional channel between main thread and one worker. Don't share a buffer between multiple workers.
|
|
218
|
+
|
|
219
|
+
3. **Parallel operations** - Use `Promise.all()` with async API (`write`/`read`) to communicate with multiple workers concurrently.
|
|
220
|
+
|
|
221
|
+
4. **Buffer pool pattern** - For dynamic worker counts, maintain a pool of buffers:
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
class BufferPool {
|
|
225
|
+
private available: SharedArrayBuffer[] = [];
|
|
226
|
+
|
|
227
|
+
acquire(size = 4096): SharedArrayBuffer {
|
|
228
|
+
return this.available.pop() ?? new SharedArrayBuffer(size);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
release(buffer: SharedArrayBuffer): void {
|
|
232
|
+
this.available.push(buffer);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
143
237
|
## Advanced: Generators
|
|
144
238
|
|
|
145
239
|
If you need fine-grained control over the transfer process (e.g., to implement a progress bar, cancellation, or custom scheduling), you can use the generator functions directly.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sabcom",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.123",
|
|
4
4
|
"description": "A TypeScript/Node.js library for inter-thread communication using SharedArrayBuffer with atomic operations for raw buffer data transfer",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -41,20 +41,20 @@
|
|
|
41
41
|
"url": "https://linkedin.com/in/3axap4eHko"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
|
-
"@eslint/js": "^9.39.
|
|
45
|
-
"@types/node": "^25.0
|
|
46
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
47
|
-
"@typescript-eslint/parser": "^8.
|
|
48
|
-
"@vitest/coverage-v8": "^4.
|
|
49
|
-
"eslint": "^9.39.
|
|
44
|
+
"@eslint/js": "^9.39.4",
|
|
45
|
+
"@types/node": "^25.5.0",
|
|
46
|
+
"@typescript-eslint/eslint-plugin": "^8.58.0",
|
|
47
|
+
"@typescript-eslint/parser": "^8.58.0",
|
|
48
|
+
"@vitest/coverage-v8": "^4.1.2",
|
|
49
|
+
"eslint": "^9.39.4",
|
|
50
50
|
"eslint-config-prettier": "^10.1.8",
|
|
51
51
|
"eslint-plugin-prettier": "^5.5.5",
|
|
52
52
|
"husky": "^9.1.7",
|
|
53
|
-
"inop": "^0.
|
|
53
|
+
"inop": "^0.9.0",
|
|
54
54
|
"prettier": "^3.8.1",
|
|
55
55
|
"typescript": "^5.9.3",
|
|
56
|
-
"typescript-eslint": "^8.
|
|
57
|
-
"vitest": "^4.
|
|
56
|
+
"typescript-eslint": "^8.58.0",
|
|
57
|
+
"vitest": "^4.1.2"
|
|
58
58
|
},
|
|
59
59
|
"scripts": {
|
|
60
60
|
"build": "rm -rf build && inop src build -i __tests__ -i *.tmp.ts && tsc --declaration --emitDeclarationOnly",
|