-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
121 lines (105 loc) · 2.56 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
const DEFAULTS = {
onError: !process.env.NODE_ENV || process.env.NODE_ENV === 'development'
|| process.env.NODE_ENV === 'test'
// eslint-disable-next-line no-console
? console.error
: () => {},
numberOfWorkers: (globalThis.navigator || navigator).hardwareConcurrency || 4,
ArrayConstructor: Array,
}
function Parallel1d(
Worker,
onUpdate,
{
onError = DEFAULTS.onError,
numberOfWorkers = DEFAULTS.numberOfWorkers,
ArrayConstructor = DEFAULTS.ArrayConstructor,
} = DEFAULTS,
) {
let workers = []
let finished
let result
this.threads = numberOfWorkers
this.working = false
const reinitializeResult = () => {
finished = 0
result = []
}
const returnUpdated = () => {
let length = 0
for (let i = 0; i < this.threads; i++) {
length += result[i].length
}
let flattened
let offset = 0
if (ArrayConstructor === Array) {
flattened = [].concat(...result)
} else {
flattened = new ArrayConstructor(length)
for (let i = 0; i < this.threads; i++) {
const addition = result[i]
flattened.set(addition, offset)
offset += addition.length
}
}
onUpdate(flattened)
reinitializeResult()
}
this.terminate = () => {
workers.forEach((worker) => {
worker.terminate()
})
workers = []
this.working = false
return this
}
const handleUpdate = (i) => ({ data }) => {
result[i] = data
finished += 1
if (finished === this.threads) {
this.working = false
returnUpdated()
}
}
const handleError = (error) => {
this.terminate()
reinitializeResult()
onError(error)
}
const initialize = () => {
for (let i = 0; i < this.threads; i++) {
workers[i] = new Worker()
workers[i].addEventListener('message', handleUpdate(i))
workers[i].addEventListener('error', handleError)
}
}
this.start = (options, jobSize) => {
if (this.working) {
onError('Workers have already started!')
return this
}
this.working = true
let from = jobSize % this.threads
const step = (jobSize - from) / this.threads
reinitializeResult()
if (!workers.length) {
initialize()
}
for (let i = 0; i < this.threads; i++) {
const to = from + step
if (!workers[i]) {
// we got an error and a pool was cleared
break
}
workers[i].postMessage({
...options,
from: i === 0 ? 0 : from,
to,
})
from = to
}
return this
}
}
Parallel1d.DEFAULTS = DEFAULTS
module.exports = Parallel1d