stardust-parallel-js 1.0.0
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 +228 -0
- package/dist/Thread.d.ts +8 -0
- package/dist/Thread.d.ts.map +1 -0
- package/dist/Thread.js +39 -0
- package/dist/Thread.js.map +1 -0
- package/dist/ThreadPool.d.ts +22 -0
- package/dist/ThreadPool.d.ts.map +1 -0
- package/dist/ThreadPool.js +95 -0
- package/dist/ThreadPool.js.map +1 -0
- package/dist/examples/thread.d.ts +2 -0
- package/dist/examples/thread.d.ts.map +1 -0
- package/dist/examples/thread.js +60 -0
- package/dist/examples/thread.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/primitives/Thread.d.ts +8 -0
- package/dist/primitives/Thread.d.ts.map +1 -0
- package/dist/primitives/Thread.js +39 -0
- package/dist/primitives/Thread.js.map +1 -0
- package/dist/primitives/ThreadPool.d.ts +22 -0
- package/dist/primitives/ThreadPool.d.ts.map +1 -0
- package/dist/primitives/ThreadPool.js +95 -0
- package/dist/primitives/ThreadPool.js.map +1 -0
- package/dist/utils/workerFactory.d.ts +3 -0
- package/dist/utils/workerFactory.d.ts.map +1 -0
- package/dist/utils/workerFactory.js +54 -0
- package/dist/utils/workerFactory.js.map +1 -0
- package/package.json +51 -0
package/README.md
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# parallel.js
|
|
2
|
+
|
|
3
|
+
Библиотека для параллельного выполнения JavaScript/TypeScript функций с использованием Worker Threads в Node.js.
|
|
4
|
+
|
|
5
|
+
## Возможности
|
|
6
|
+
|
|
7
|
+
- ✨ Простой API для параллельного выполнения функций
|
|
8
|
+
- 🔄 Пул потоков для эффективного управления ресурсами
|
|
9
|
+
- 🚀 Отдельные потоки для разовых задач
|
|
10
|
+
- 📦 TypeScript поддержка из коробки
|
|
11
|
+
- 🛡️ Автоматическое восстановление упавших потоков
|
|
12
|
+
- ⚡ Асинхронная обработка задач с очередью
|
|
13
|
+
|
|
14
|
+
## Установка
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install parallel.js
|
|
18
|
+
# или
|
|
19
|
+
pnpm install parallel.js
|
|
20
|
+
# или
|
|
21
|
+
yarn add parallel.js
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Использование
|
|
25
|
+
|
|
26
|
+
### ThreadPool - Пул потоков
|
|
27
|
+
|
|
28
|
+
Используйте `ThreadPool` для выполнения множества задач с ограниченным количеством потоков:
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
import { ThreadPool } from 'parallel.js';
|
|
32
|
+
|
|
33
|
+
// Создаем пул из 4 потоков
|
|
34
|
+
const pool = new ThreadPool(4);
|
|
35
|
+
|
|
36
|
+
// Выполнение одной задачи
|
|
37
|
+
const result = await pool.execute(
|
|
38
|
+
(n: number) => {
|
|
39
|
+
// Тяжелые вычисления
|
|
40
|
+
let sum = 0;
|
|
41
|
+
for (let i = 0; i < n; i++) {
|
|
42
|
+
sum += Math.sqrt(i);
|
|
43
|
+
}
|
|
44
|
+
return sum;
|
|
45
|
+
},
|
|
46
|
+
[1000000]
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
console.log(result);
|
|
50
|
+
|
|
51
|
+
// Параллельная обработка массива
|
|
52
|
+
const numbers = [1, 2, 3, 4, 5, 6, 7, 8];
|
|
53
|
+
const squares = await pool.map(numbers, (n: number) => n * n);
|
|
54
|
+
console.log(squares); // [1, 4, 9, 16, 25, 36, 49, 64]
|
|
55
|
+
|
|
56
|
+
// Не забудьте остановить пул
|
|
57
|
+
await pool.terminate();
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Thread - Отдельный поток
|
|
61
|
+
|
|
62
|
+
Используйте `Thread` для разовых задач:
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
import { Thread } from 'parallel.js';
|
|
66
|
+
|
|
67
|
+
// Создаем поток для выполнения функции
|
|
68
|
+
const thread = new Thread(
|
|
69
|
+
(text: string) => {
|
|
70
|
+
return text.toUpperCase();
|
|
71
|
+
},
|
|
72
|
+
['hello world']
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
// Ждем результат
|
|
76
|
+
const result = await thread.join();
|
|
77
|
+
console.log(result); // "HELLO WORLD"
|
|
78
|
+
|
|
79
|
+
// Стрелочные функции также поддерживаются
|
|
80
|
+
const thread2 = new Thread(x => x * 2, [21]);
|
|
81
|
+
const result2 = await thread2.join();
|
|
82
|
+
console.log(result2); // 42
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## API
|
|
86
|
+
|
|
87
|
+
### ThreadPool
|
|
88
|
+
|
|
89
|
+
#### `constructor(size: number)`
|
|
90
|
+
Создает пул потоков заданного размера.
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
const pool = new ThreadPool(4);
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
#### `execute<TArgs, TResult>(fn: (...args: TArgs) => TResult, args?: TArgs): Promise<TResult>`
|
|
97
|
+
Выполняет функцию в доступном потоке из пула.
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
const result = await pool.execute(
|
|
101
|
+
#### `map<T, R>(items: T[], fn: (item: T) => R): Promise<R[]>`
|
|
102
|
+
Применяет функцию к каждому элементу массива параллельно.
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
// Стрелочная функция
|
|
106
|
+
const results = await pool.map([1, 2, 3], n => n * 2);
|
|
107
|
+
|
|
108
|
+
// Обычная функция
|
|
109
|
+
const results2 = await pool.map([1, 2, 3], function(n) { return n * 2; });
|
|
110
|
+
```# `map<T, R>(items: T[], fn: (item: T) => R): Promise<R[]>`
|
|
111
|
+
Применяет функцию к каждому элементу массива параллельно.
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
const results = await pool.map([1, 2, 3], (n) => n * 2);
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
#### `terminate(): Promise<void>`
|
|
118
|
+
Останавливает все потоки и освобождает ресурсы.
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
await pool.terminate();
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Thread
|
|
125
|
+
|
|
126
|
+
#### `constructor<T, TArgs>(fn: (...args: TArgs) => T, args?: TArgs)`
|
|
127
|
+
Создает новый поток для выполнения функции.
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
const thread = new Thread((x: number) => x * x, [5]);
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
#### `join(): Promise<T>`
|
|
134
|
+
Ожидает завершения выполнения и возвращает результат. Автоматически завершает поток.
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
const result = await thread.join();
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Примеры
|
|
141
|
+
|
|
142
|
+
### Обработка больших данных
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
import { ThreadPool } from 'parallel.js';
|
|
146
|
+
|
|
147
|
+
const pool = new ThreadPool(8);
|
|
148
|
+
|
|
149
|
+
const data = Array.from({ length: 10000 }, (_, i) => i);
|
|
150
|
+
|
|
151
|
+
const processed = await pool.map(data, (item: number) => {
|
|
152
|
+
// Сложная обработка каждого элемента
|
|
153
|
+
return Math.sin(item) * Math.cos(item);
|
|
154
|
+
});
|
|
155
|
+
### Вычисление чисел Фибоначчи
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
import { ThreadPool } from 'parallel.js';
|
|
159
|
+
|
|
160
|
+
const pool = new ThreadPool(4);
|
|
161
|
+
|
|
162
|
+
const numbers = [35, 36, 37, 38, 39, 40];
|
|
163
|
+
|
|
164
|
+
const results = await pool.map(numbers, n => {
|
|
165
|
+
function fibonacci(num) {
|
|
166
|
+
if (num <= 1) return num;
|
|
167
|
+
return fibonacci(num - 1) + fibonacci(num - 2);
|
|
168
|
+
}
|
|
169
|
+
return fibonacci(n);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
console.log(results); // [9227465, 14930352, 24157817, ...]
|
|
173
|
+
|
|
174
|
+
await pool.terminate();
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Использование встроенных модулей Node.js
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
import { ThreadPool } from 'parallel.js';
|
|
181
|
+
|
|
182
|
+
const pool = new ThreadPool(4);
|
|
183
|
+
|
|
184
|
+
// require() доступен внутри функций
|
|
185
|
+
const result = await pool.execute(() => {
|
|
186
|
+
const fs = require('fs');
|
|
187
|
+
const path = require('path');
|
|
188
|
+
return path.join('folder', 'file.txt');
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
console.log(result); // 'folder/file.txt' или 'folder\\file.txt'
|
|
192
|
+
|
|
193
|
+
await pool.terminate();
|
|
194
|
+
```eturn response.json();
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
await pool.terminate();
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Важные замечания
|
|
201
|
+
|
|
202
|
+
- 🔒 Функции, передаваемые в потоки, выполняются в изолированном контексте
|
|
203
|
+
- 📦 Все аргументы и результаты должны быть сериализуемыми (передаются через структурированное клонирование)
|
|
204
|
+
- 🚫 Нельзя использовать замыкания - функции не имеют доступа к внешним переменным из основного потока
|
|
205
|
+
- ✅ Поддерживаются как обычные функции (`function`), так и стрелочные (`=>`)
|
|
206
|
+
- ✅ `require()` и встроенные модули Node.js доступны внутри функций
|
|
207
|
+
- ⚡ Worker Threads лучше всего подходят для CPU-интенсивных задач
|
|
208
|
+
|
|
209
|
+
## Требования
|
|
210
|
+
|
|
211
|
+
- Node.js >= 14.0.0 (с поддержкой Worker Threads)
|
|
212
|
+
|
|
213
|
+
## Лицензия
|
|
214
|
+
|
|
215
|
+
ISC
|
|
216
|
+
|
|
217
|
+
## Разработка
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
# Установка зависимостей
|
|
221
|
+
pnpm install
|
|
222
|
+
|
|
223
|
+
# Запуск тестов
|
|
224
|
+
pnpm test
|
|
225
|
+
|
|
226
|
+
# Сборка
|
|
227
|
+
pnpm build
|
|
228
|
+
```
|
package/dist/Thread.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Thread.d.ts","sourceRoot":"","sources":["../src/Thread.ts"],"names":[],"mappings":"AAGA,cAAM,MAAM,CAAC,CAAC,EAAE,KAAK,SAAS,OAAO,EAAE,GAAG,OAAO,EAAE;IAC/C,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAAa;gBAEhB,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,KAAK,CAAC,EAAE,IAAI,GAAE,KAA8B;IAwBrE,IAAI,IAAI,OAAO,CAAC,CAAC,CAAC;CAQ3B;AAED,OAAO,EAAE,MAAM,EAAE,CAAA"}
|
package/dist/Thread.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Worker } from "node:worker_threads";
|
|
2
|
+
import { createWorker } from "@/utils/workerFactory.js";
|
|
3
|
+
class Thread {
|
|
4
|
+
worker;
|
|
5
|
+
promise;
|
|
6
|
+
constructor(fn, args = []) {
|
|
7
|
+
this.worker = createWorker();
|
|
8
|
+
this.promise = new Promise((resolve, reject) => {
|
|
9
|
+
this.worker.on('message', (res) => {
|
|
10
|
+
if (res.success) {
|
|
11
|
+
resolve(res.result);
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
reject(new Error(res.error));
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
this.worker.on('error', (err) => {
|
|
18
|
+
reject(err);
|
|
19
|
+
});
|
|
20
|
+
this.worker.on('exit', (code) => {
|
|
21
|
+
if (code !== 0) {
|
|
22
|
+
reject(new Error(`Worker stopped with exit code ${code}`));
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
this.worker.postMessage({ fn: fn.toString(), args });
|
|
27
|
+
}
|
|
28
|
+
async join() {
|
|
29
|
+
try {
|
|
30
|
+
const result = await this.promise;
|
|
31
|
+
return result;
|
|
32
|
+
}
|
|
33
|
+
finally {
|
|
34
|
+
this.worker.terminate();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
export { Thread };
|
|
39
|
+
//# sourceMappingURL=Thread.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Thread.js","sourceRoot":"","sources":["../src/Thread.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAExD,MAAM,MAAM;IACA,MAAM,CAAS;IACf,OAAO,CAAa;IAE5B,YAAY,EAAyB,EAAE,OAAc,EAAsB;QACvE,IAAI,CAAC,MAAM,GAAG,YAAY,EAAE,CAAC;QAE7B,IAAI,CAAC,OAAO,GAAG,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC9C,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,GAAqD,EAAE,EAAE;gBAChF,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;oBACd,OAAO,CAAC,GAAG,CAAC,MAAW,CAAC,CAAC;gBAC7B,CAAC;qBAAM,CAAC;oBACJ,MAAM,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;gBACjC,CAAC;YACL,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;gBAC5B,MAAM,CAAC,GAAG,CAAC,CAAC;YAChB,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;gBAC5B,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;oBACb,MAAM,CAAC,IAAI,KAAK,CAAC,iCAAiC,IAAI,EAAE,CAAC,CAAC,CAAC;gBAC/D,CAAC;YACL,CAAC,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IACzD,CAAC;IAED,KAAK,CAAC,IAAI;QACN,IAAI,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC;YAClC,OAAO,MAAM,CAAC;QAClB,CAAC;gBAAS,CAAC;YACP,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;QAC5B,CAAC;IACL,CAAC;CACJ;AAED,OAAO,EAAE,MAAM,EAAE,CAAA"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export declare class ThreadPool {
|
|
2
|
+
private size;
|
|
3
|
+
private workers;
|
|
4
|
+
private availableWorkers;
|
|
5
|
+
private taskQueue;
|
|
6
|
+
private workerTasks;
|
|
7
|
+
constructor(size: number);
|
|
8
|
+
private initWorkers;
|
|
9
|
+
private setupWorkerHandlers;
|
|
10
|
+
private recoverWorker;
|
|
11
|
+
private processQueue;
|
|
12
|
+
execute<TArgs extends unknown[], TResult>(fn: (...args: TArgs) => TResult, args?: TArgs): Promise<TResult>;
|
|
13
|
+
map<T, R>(items: T[], fn: (item: T) => R): Promise<R[]>;
|
|
14
|
+
getStats(): {
|
|
15
|
+
totalWorkers: number;
|
|
16
|
+
availableWorkers: number;
|
|
17
|
+
busyWorkers: number;
|
|
18
|
+
queuedTasks: number;
|
|
19
|
+
};
|
|
20
|
+
terminate(): Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=ThreadPool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ThreadPool.d.ts","sourceRoot":"","sources":["../src/ThreadPool.ts"],"names":[],"mappings":"AAWA,qBAAa,UAAU;IAMP,OAAO,CAAC,IAAI;IALxB,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,gBAAgB,CAAgB;IACxC,OAAO,CAAC,SAAS,CAA8B;IAC/C,OAAO,CAAC,WAAW,CAAoC;gBAEnC,IAAI,EAAE,MAAM;IAIhC,OAAO,CAAC,WAAW;IASnB,OAAO,CAAC,mBAAmB;IA0B3B,OAAO,CAAC,aAAa;IAYrB,OAAO,CAAC,YAAY;IAUd,OAAO,CAAC,KAAK,SAAS,OAAO,EAAE,EAAE,OAAO,EAC1C,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,KAAK,OAAO,EAC/B,IAAI,GAAE,KAA8B,GACrC,OAAO,CAAC,OAAO,CAAC;IAab,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IAM7D,QAAQ;;;;;;IASF,SAAS;CASlB"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { Worker } from "node:worker_threads";
|
|
2
|
+
import { createWorker } from "@/utils/workerFactory.js";
|
|
3
|
+
import { Queue } from "@datastructures-js/queue";
|
|
4
|
+
export class ThreadPool {
|
|
5
|
+
size;
|
|
6
|
+
workers = [];
|
|
7
|
+
availableWorkers = [];
|
|
8
|
+
taskQueue = new Queue();
|
|
9
|
+
workerTasks = new Map();
|
|
10
|
+
constructor(size) {
|
|
11
|
+
this.size = size;
|
|
12
|
+
this.initWorkers();
|
|
13
|
+
}
|
|
14
|
+
initWorkers() {
|
|
15
|
+
for (let i = 0; i < this.size; i++) {
|
|
16
|
+
const worker = createWorker();
|
|
17
|
+
this.setupWorkerHandlers(worker);
|
|
18
|
+
this.workers.push(worker);
|
|
19
|
+
this.availableWorkers.push(worker);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
setupWorkerHandlers(worker) {
|
|
23
|
+
worker.on('message', (res) => {
|
|
24
|
+
const task = this.workerTasks.get(worker);
|
|
25
|
+
if (!task)
|
|
26
|
+
return;
|
|
27
|
+
if (res.success) {
|
|
28
|
+
task.resolve(res.result);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
task.reject(new Error(res.error));
|
|
32
|
+
}
|
|
33
|
+
this.workerTasks.delete(worker);
|
|
34
|
+
this.availableWorkers.push(worker);
|
|
35
|
+
this.processQueue();
|
|
36
|
+
});
|
|
37
|
+
worker.on('error', (err) => {
|
|
38
|
+
const task = this.workerTasks.get(worker);
|
|
39
|
+
if (task) {
|
|
40
|
+
task.reject(err);
|
|
41
|
+
this.workerTasks.delete(worker);
|
|
42
|
+
}
|
|
43
|
+
this.recoverWorker(worker);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
recoverWorker(crashedWorker) {
|
|
47
|
+
this.workers = this.workers.filter(worker => worker !== crashedWorker);
|
|
48
|
+
this.availableWorkers = this.availableWorkers.filter(worker => worker !== crashedWorker);
|
|
49
|
+
crashedWorker.terminate();
|
|
50
|
+
const newWorker = createWorker();
|
|
51
|
+
this.setupWorkerHandlers(newWorker);
|
|
52
|
+
this.workers.push(newWorker);
|
|
53
|
+
this.availableWorkers.push(newWorker);
|
|
54
|
+
this.processQueue();
|
|
55
|
+
}
|
|
56
|
+
processQueue() {
|
|
57
|
+
while (!this.taskQueue.isEmpty() && this.availableWorkers.length > 0) {
|
|
58
|
+
const worker = this.availableWorkers.pop();
|
|
59
|
+
const task = this.taskQueue.dequeue();
|
|
60
|
+
this.workerTasks.set(worker, task);
|
|
61
|
+
worker.postMessage({ fn: task.fn.toString(), args: task.args });
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async execute(fn, args = []) {
|
|
65
|
+
return new Promise((resolve, reject) => {
|
|
66
|
+
const task = {
|
|
67
|
+
fn: fn.toString(),
|
|
68
|
+
args,
|
|
69
|
+
resolve: resolve,
|
|
70
|
+
reject
|
|
71
|
+
};
|
|
72
|
+
this.taskQueue.enqueue(task);
|
|
73
|
+
this.processQueue();
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
async map(items, fn) {
|
|
77
|
+
return Promise.all(items.map(item => this.execute(fn, [item])));
|
|
78
|
+
}
|
|
79
|
+
getStats() {
|
|
80
|
+
return {
|
|
81
|
+
totalWorkers: this.workers.length,
|
|
82
|
+
availableWorkers: this.availableWorkers.length,
|
|
83
|
+
busyWorkers: this.workers.length - this.availableWorkers.length,
|
|
84
|
+
queuedTasks: this.taskQueue.size(),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
async terminate() {
|
|
88
|
+
await Promise.all(this.workers.map(w => w.terminate()));
|
|
89
|
+
this.workers = [];
|
|
90
|
+
this.availableWorkers = [];
|
|
91
|
+
this.taskQueue = new Queue();
|
|
92
|
+
this.workerTasks.clear();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=ThreadPool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ThreadPool.js","sourceRoot":"","sources":["../src/ThreadPool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"thread.d.ts","sourceRoot":"","sources":["../../src/examples/thread.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Thread } from "@/Thread.js";
|
|
2
|
+
async function main() {
|
|
3
|
+
console.log("🚀 Запуск примера с потоками...\n");
|
|
4
|
+
// Создаем поток для выполнения тяжелых вычислений
|
|
5
|
+
console.log("⏳ Запускаем вычисление факториала 20 в отдельном потоке...");
|
|
6
|
+
const factorialThread = new Thread(function (n) {
|
|
7
|
+
function factorial(num) {
|
|
8
|
+
if (num <= 1)
|
|
9
|
+
return 1;
|
|
10
|
+
return num * factorial(num - 1);
|
|
11
|
+
}
|
|
12
|
+
// Симулируем долгое вычисление
|
|
13
|
+
const start = Date.now();
|
|
14
|
+
const result = factorial(n);
|
|
15
|
+
const duration = Date.now() - start;
|
|
16
|
+
return { result, duration };
|
|
17
|
+
}, [20]);
|
|
18
|
+
// Создаем поток для обработки массива
|
|
19
|
+
console.log("⏳ Запускаем обработку массива в отдельном потоке...");
|
|
20
|
+
const arrayThread = new Thread(function (arr) {
|
|
21
|
+
const sum = arr.reduce(function (a, b) { return a + b; }, 0);
|
|
22
|
+
const avg = sum / arr.length;
|
|
23
|
+
const max = Math.max(...arr);
|
|
24
|
+
const min = Math.min(...arr);
|
|
25
|
+
return { sum, avg, max, min };
|
|
26
|
+
}, [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]);
|
|
27
|
+
// Создаем поток для проверки простых чисел
|
|
28
|
+
console.log("⏳ Запускаем поиск простых чисел в отдельном потоке...");
|
|
29
|
+
const primeThread = new Thread(function (limit) {
|
|
30
|
+
function isPrime(num) {
|
|
31
|
+
if (num < 2)
|
|
32
|
+
return false;
|
|
33
|
+
for (let i = 2; i <= Math.sqrt(num); i++) {
|
|
34
|
+
if (num % i === 0)
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
const primes = [];
|
|
40
|
+
for (let i = 2; i <= limit; i++) {
|
|
41
|
+
if (isPrime(i))
|
|
42
|
+
primes.push(i);
|
|
43
|
+
}
|
|
44
|
+
return primes;
|
|
45
|
+
}, [100]);
|
|
46
|
+
console.log("\n⏰ Главный поток продолжает работу, пока потоки выполняются...");
|
|
47
|
+
console.log("✅ Главный поток свободен для других задач!\n");
|
|
48
|
+
// Ждем результаты от всех потоков
|
|
49
|
+
console.log("🔄 Ожидаем результаты от потоков...\n");
|
|
50
|
+
const factorialResult = await factorialThread.join();
|
|
51
|
+
console.log(`✨ Факториал: ${factorialResult.result} (выполнено за ${factorialResult.duration}мс)`);
|
|
52
|
+
const arrayResult = await arrayThread.join();
|
|
53
|
+
console.log(`✨ Статистика массива:`, arrayResult);
|
|
54
|
+
const primeResult = await primeThread.join();
|
|
55
|
+
console.log(`✨ Простые числа до 100: ${primeResult.join(', ')}`);
|
|
56
|
+
console.log(` Найдено ${primeResult.length} простых чисел`);
|
|
57
|
+
console.log("\n🎉 Все потоки завершены!");
|
|
58
|
+
}
|
|
59
|
+
main();
|
|
60
|
+
//# sourceMappingURL=thread.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"thread.js","sourceRoot":"","sources":["../../src/examples/thread.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Thread.d.ts","sourceRoot":"","sources":["../../src/primitives/Thread.ts"],"names":[],"mappings":"AAGA,cAAM,MAAM,CAAC,CAAC,EAAE,KAAK,SAAS,OAAO,EAAE,GAAG,OAAO,EAAE;IAC/C,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAAa;gBAEhB,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,KAAK,CAAC,EAAE,IAAI,GAAE,KAA8B;IAwBrE,IAAI,IAAI,OAAO,CAAC,CAAC,CAAC;CAQ3B;AAED,OAAO,EAAE,MAAM,EAAE,CAAA"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Worker } from "node:worker_threads";
|
|
2
|
+
import { createWorker } from "@/utils/workerFactory.js";
|
|
3
|
+
class Thread {
|
|
4
|
+
worker;
|
|
5
|
+
promise;
|
|
6
|
+
constructor(fn, args = []) {
|
|
7
|
+
this.worker = createWorker();
|
|
8
|
+
this.promise = new Promise((resolve, reject) => {
|
|
9
|
+
this.worker.on('message', (res) => {
|
|
10
|
+
if (res.success) {
|
|
11
|
+
resolve(res.result);
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
reject(new Error(res.error));
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
this.worker.on('error', (err) => {
|
|
18
|
+
reject(err);
|
|
19
|
+
});
|
|
20
|
+
this.worker.on('exit', (code) => {
|
|
21
|
+
if (code !== 0) {
|
|
22
|
+
reject(new Error(`Worker stopped with exit code ${code}`));
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
this.worker.postMessage({ fn: fn.toString(), args });
|
|
27
|
+
}
|
|
28
|
+
async join() {
|
|
29
|
+
try {
|
|
30
|
+
const result = await this.promise;
|
|
31
|
+
return result;
|
|
32
|
+
}
|
|
33
|
+
finally {
|
|
34
|
+
this.worker.terminate();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
export { Thread };
|
|
39
|
+
//# sourceMappingURL=Thread.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Thread.js","sourceRoot":"","sources":["../../src/primitives/Thread.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAExD,MAAM,MAAM;IACA,MAAM,CAAS;IACf,OAAO,CAAa;IAE5B,YAAY,EAAyB,EAAE,OAAc,EAAsB;QACvE,IAAI,CAAC,MAAM,GAAG,YAAY,EAAE,CAAC;QAE7B,IAAI,CAAC,OAAO,GAAG,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC9C,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,GAAqD,EAAE,EAAE;gBAChF,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;oBACd,OAAO,CAAC,GAAG,CAAC,MAAW,CAAC,CAAC;gBAC7B,CAAC;qBAAM,CAAC;oBACJ,MAAM,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;gBACjC,CAAC;YACL,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;gBAC5B,MAAM,CAAC,GAAG,CAAC,CAAC;YAChB,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;gBAC5B,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;oBACb,MAAM,CAAC,IAAI,KAAK,CAAC,iCAAiC,IAAI,EAAE,CAAC,CAAC,CAAC;gBAC/D,CAAC;YACL,CAAC,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IACzD,CAAC;IAED,KAAK,CAAC,IAAI;QACN,IAAI,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC;YAClC,OAAO,MAAM,CAAC;QAClB,CAAC;gBAAS,CAAC;YACP,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;QAC5B,CAAC;IACL,CAAC;CACJ;AAED,OAAO,EAAE,MAAM,EAAE,CAAA"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export declare class ThreadPool {
|
|
2
|
+
private size;
|
|
3
|
+
private workers;
|
|
4
|
+
private availableWorkers;
|
|
5
|
+
private taskQueue;
|
|
6
|
+
private workerTasks;
|
|
7
|
+
constructor(size: number);
|
|
8
|
+
private initWorkers;
|
|
9
|
+
private setupWorkerHandlers;
|
|
10
|
+
private recoverWorker;
|
|
11
|
+
private processQueue;
|
|
12
|
+
execute<TArgs extends unknown[], TResult>(fn: (...args: TArgs) => TResult, args?: TArgs): Promise<TResult>;
|
|
13
|
+
map<T, R>(items: T[], fn: (item: T) => R): Promise<R[]>;
|
|
14
|
+
getStats(): {
|
|
15
|
+
totalWorkers: number;
|
|
16
|
+
availableWorkers: number;
|
|
17
|
+
busyWorkers: number;
|
|
18
|
+
queuedTasks: number;
|
|
19
|
+
};
|
|
20
|
+
terminate(): Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=ThreadPool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ThreadPool.d.ts","sourceRoot":"","sources":["../../src/primitives/ThreadPool.ts"],"names":[],"mappings":"AAWA,qBAAa,UAAU;IAMP,OAAO,CAAC,IAAI;IALxB,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,gBAAgB,CAAgB;IACxC,OAAO,CAAC,SAAS,CAA8B;IAC/C,OAAO,CAAC,WAAW,CAAoC;gBAEnC,IAAI,EAAE,MAAM;IAIhC,OAAO,CAAC,WAAW;IASnB,OAAO,CAAC,mBAAmB;IA0B3B,OAAO,CAAC,aAAa;IAYrB,OAAO,CAAC,YAAY;IAUd,OAAO,CAAC,KAAK,SAAS,OAAO,EAAE,EAAE,OAAO,EAC1C,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,KAAK,OAAO,EAC/B,IAAI,GAAE,KAA8B,GACrC,OAAO,CAAC,OAAO,CAAC;IAab,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IAM7D,QAAQ;;;;;;IASF,SAAS;CASlB"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { Worker } from "node:worker_threads";
|
|
2
|
+
import { createWorker } from "@/utils/workerFactory.js";
|
|
3
|
+
import { Queue } from "@datastructures-js/queue";
|
|
4
|
+
export class ThreadPool {
|
|
5
|
+
size;
|
|
6
|
+
workers = [];
|
|
7
|
+
availableWorkers = [];
|
|
8
|
+
taskQueue = new Queue();
|
|
9
|
+
workerTasks = new Map();
|
|
10
|
+
constructor(size) {
|
|
11
|
+
this.size = size;
|
|
12
|
+
this.initWorkers();
|
|
13
|
+
}
|
|
14
|
+
initWorkers() {
|
|
15
|
+
for (let i = 0; i < this.size; i++) {
|
|
16
|
+
const worker = createWorker();
|
|
17
|
+
this.setupWorkerHandlers(worker);
|
|
18
|
+
this.workers.push(worker);
|
|
19
|
+
this.availableWorkers.push(worker);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
setupWorkerHandlers(worker) {
|
|
23
|
+
worker.on('message', (res) => {
|
|
24
|
+
const task = this.workerTasks.get(worker);
|
|
25
|
+
if (!task)
|
|
26
|
+
return;
|
|
27
|
+
if (res.success) {
|
|
28
|
+
task.resolve(res.result);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
task.reject(new Error(res.error));
|
|
32
|
+
}
|
|
33
|
+
this.workerTasks.delete(worker);
|
|
34
|
+
this.availableWorkers.push(worker);
|
|
35
|
+
this.processQueue();
|
|
36
|
+
});
|
|
37
|
+
worker.on('error', (err) => {
|
|
38
|
+
const task = this.workerTasks.get(worker);
|
|
39
|
+
if (task) {
|
|
40
|
+
task.reject(err);
|
|
41
|
+
this.workerTasks.delete(worker);
|
|
42
|
+
}
|
|
43
|
+
this.recoverWorker(worker);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
recoverWorker(crashedWorker) {
|
|
47
|
+
this.workers = this.workers.filter(worker => worker !== crashedWorker);
|
|
48
|
+
this.availableWorkers = this.availableWorkers.filter(worker => worker !== crashedWorker);
|
|
49
|
+
crashedWorker.terminate();
|
|
50
|
+
const newWorker = createWorker();
|
|
51
|
+
this.setupWorkerHandlers(newWorker);
|
|
52
|
+
this.workers.push(newWorker);
|
|
53
|
+
this.availableWorkers.push(newWorker);
|
|
54
|
+
this.processQueue();
|
|
55
|
+
}
|
|
56
|
+
processQueue() {
|
|
57
|
+
while (!this.taskQueue.isEmpty() && this.availableWorkers.length > 0) {
|
|
58
|
+
const worker = this.availableWorkers.pop();
|
|
59
|
+
const task = this.taskQueue.dequeue();
|
|
60
|
+
this.workerTasks.set(worker, task);
|
|
61
|
+
worker.postMessage({ fn: task.fn.toString(), args: task.args });
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async execute(fn, args = []) {
|
|
65
|
+
return new Promise((resolve, reject) => {
|
|
66
|
+
const task = {
|
|
67
|
+
fn: fn.toString(),
|
|
68
|
+
args,
|
|
69
|
+
resolve: resolve,
|
|
70
|
+
reject
|
|
71
|
+
};
|
|
72
|
+
this.taskQueue.enqueue(task);
|
|
73
|
+
this.processQueue();
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
async map(items, fn) {
|
|
77
|
+
return Promise.all(items.map(item => this.execute(fn, [item])));
|
|
78
|
+
}
|
|
79
|
+
getStats() {
|
|
80
|
+
return {
|
|
81
|
+
totalWorkers: this.workers.length,
|
|
82
|
+
availableWorkers: this.availableWorkers.length,
|
|
83
|
+
busyWorkers: this.workers.length - this.availableWorkers.length,
|
|
84
|
+
queuedTasks: this.taskQueue.size(),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
async terminate() {
|
|
88
|
+
await Promise.all(this.workers.map(w => w.terminate()));
|
|
89
|
+
this.workers = [];
|
|
90
|
+
this.availableWorkers = [];
|
|
91
|
+
this.taskQueue = new Queue();
|
|
92
|
+
this.workerTasks.clear();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=ThreadPool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ThreadPool.js","sourceRoot":"","sources":["../../src/primitives/ThreadPool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workerFactory.d.ts","sourceRoot":"","sources":["../../src/utils/workerFactory.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AA6C7C,wBAAgB,YAAY,WAG3B"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Worker Factory
|
|
3
|
+
Creates a new Worker instance with predefined code to execute functions.
|
|
4
|
+
Worker returns results or errors back to the main thread.
|
|
5
|
+
Supports both regular and arrow functions.
|
|
6
|
+
*/
|
|
7
|
+
import { Worker } from "node:worker_threads";
|
|
8
|
+
const workerCode = `
|
|
9
|
+
const { parentPort } = require('worker_threads');
|
|
10
|
+
parentPort.on('message', ({ fn, args }) => {
|
|
11
|
+
try {
|
|
12
|
+
// Remove __name helper calls added by TypeScript
|
|
13
|
+
let cleanFn = fn.replace(/__name\\([^)]+\\);?/g, '').trim();
|
|
14
|
+
|
|
15
|
+
// Convert arrow functions to regular functions
|
|
16
|
+
// Handles: (a, b) => expr or (a, b) => { ... }
|
|
17
|
+
const arrowMatch = cleanFn.match(/^\\(([^)]*)\\)\\s*=>\\s*(.+)$/s);
|
|
18
|
+
if (arrowMatch) {
|
|
19
|
+
const params = arrowMatch[1];
|
|
20
|
+
const body = arrowMatch[2].trim();
|
|
21
|
+
|
|
22
|
+
// Check if body is wrapped in braces or is an expression
|
|
23
|
+
if (body.startsWith('{') && body.endsWith('}')) {
|
|
24
|
+
cleanFn = \`function(\${params}) \${body}\`;
|
|
25
|
+
} else {
|
|
26
|
+
cleanFn = \`function(\${params}) { return \${body} }\`;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
// Handle single parameter arrow functions: x => expr
|
|
30
|
+
const singleArrowMatch = cleanFn.match(/^([a-zA-Z_$][a-zA-Z0-9_$]*)\\s*=>\\s*(.+)$/s);
|
|
31
|
+
if (singleArrowMatch) {
|
|
32
|
+
const param = singleArrowMatch[1];
|
|
33
|
+
const body = singleArrowMatch[2].trim();
|
|
34
|
+
|
|
35
|
+
if (body.startsWith('{') && body.endsWith('}')) {
|
|
36
|
+
cleanFn = \`function(\${param}) \${body}\`;
|
|
37
|
+
} else {
|
|
38
|
+
cleanFn = \`function(\${param}) { return \${body} }\`;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const func = eval('(' + cleanFn + ')');
|
|
43
|
+
const result = func(...args);
|
|
44
|
+
parentPort.postMessage({ success: true, result });
|
|
45
|
+
} catch (error) {
|
|
46
|
+
parentPort.postMessage({ success: false, error: error.message });
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
`;
|
|
50
|
+
export function createWorker() {
|
|
51
|
+
const worker = new Worker(workerCode, { eval: true });
|
|
52
|
+
return worker;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=workerFactory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workerFactory.js","sourceRoot":"","sources":["../../src/utils/workerFactory.ts"],"names":[],"mappings":"AAAA;;;;;EAKE;AAEF,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAE7C,MAAM,UAAU,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;SAyCV,CAAC;AAEV,MAAM,UAAU,YAAY;IACxB,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,UAAU,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACtD,OAAO,MAAM,CAAC;AAClB,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "stardust-parallel-js",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Simple parallel execution library for Node.js using Worker Threads. Execute CPU-intensive tasks with thread pools and isolated workers. Supports both regular and arrow functions.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"README.md"
|
|
10
|
+
],
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/b1411/parallel.js.git"
|
|
14
|
+
},
|
|
15
|
+
"type": "module",
|
|
16
|
+
"scripts": {
|
|
17
|
+
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
|
|
18
|
+
"build": "tsc -p ."
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"parallel",
|
|
22
|
+
"worker",
|
|
23
|
+
"threads",
|
|
24
|
+
"worker-threads",
|
|
25
|
+
"pool",
|
|
26
|
+
"threadpool",
|
|
27
|
+
"async",
|
|
28
|
+
"concurrent",
|
|
29
|
+
"cpu",
|
|
30
|
+
"performance",
|
|
31
|
+
"multithread",
|
|
32
|
+
"typescript"
|
|
33
|
+
],
|
|
34
|
+
"author": "b1411",
|
|
35
|
+
"license": "MIT",
|
|
36
|
+
"packageManager": "pnpm@10.23.0",
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@eslint/js": "^9.39.2",
|
|
39
|
+
"@types/jest": "^30.0.0",
|
|
40
|
+
"@types/node": "^25.0.8",
|
|
41
|
+
"eslint": "^9.39.2",
|
|
42
|
+
"jest": "^30.2.0",
|
|
43
|
+
"ts-jest": "^29.4.6",
|
|
44
|
+
"tsx": "^4.21.0",
|
|
45
|
+
"typescript": "^5.9.3",
|
|
46
|
+
"typescript-eslint": "^8.53.0"
|
|
47
|
+
},
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"@datastructures-js/queue": "^4.3.0"
|
|
50
|
+
}
|
|
51
|
+
}
|