1 import { randomInt } from 'node:crypto'
2 import { bench, group, run } from 'tatami-ng'
6 * @param numberOfWorkers
7 * @param maxNumberOfTasksPerWorker
10 function generateRandomTasksMap (
12 maxNumberOfTasksPerWorker = 10
15 for (let i = 0; i < numberOfWorkers; i++) {
16 const task = [i, randomInt(maxNumberOfTasksPerWorker)]
19 return new Map(tasksArray)
22 const tasksMap = generateRandomTasksMap(60, 20)
29 function loopSelect (tasksMap) {
31 let minValue = Number.POSITIVE_INFINITY
32 for (const [key, value] of tasksMap) {
35 } else if (value < minValue) {
40 return [minKey, minValue]
48 function arraySortSelect (tasksMap) {
49 const tasksArray = Array.from(tasksMap)
50 return tasksArray.sort((a, b) => {
53 } else if (a[1] > b[1]) {
60 const defaultComparator = (a, b) => {
64 const defaultPivotIndexSelect = (leftIndex, rightIndex) => {
65 return leftIndex + Math.floor((rightIndex - leftIndex) / 2)
68 const randomPivotIndexSelect = (leftIndex, rightIndex) => {
69 return randomInt(leftIndex, rightIndex)
78 function swap (array, index1, index2) {
79 const tmp = array[index1]
80 array[index1] = array[index2]
98 compare = defaultComparator
100 const pivotValue = array[pivotIndex]
101 swap(array, pivotIndex, rightIndex)
102 let storeIndex = leftIndex
103 for (let i = leftIndex; i < rightIndex; i++) {
104 if (compare(array[i], pivotValue)) {
105 swap(array, storeIndex, i)
109 swap(array, rightIndex, storeIndex)
120 * @param pivotIndexSelect
123 function selectLoop (
128 compare = defaultComparator,
129 pivotIndexSelect = defaultPivotIndexSelect
132 if (leftIndex === rightIndex) return array[leftIndex]
133 let pivotIndex = pivotIndexSelect(leftIndex, rightIndex)
134 pivotIndex = partition(array, leftIndex, rightIndex, pivotIndex, compare)
135 if (k === pivotIndex) {
137 } else if (k < pivotIndex) {
138 rightIndex = pivotIndex - 1
140 leftIndex = pivotIndex + 1
152 * @param pivotIndexSelect
155 function selectRecursion (
160 compare = defaultComparator,
161 pivotIndexSelect = defaultPivotIndexSelect
163 if (leftIndex === rightIndex) return array[leftIndex]
164 let pivotIndex = pivotIndexSelect(leftIndex, rightIndex)
165 pivotIndex = partition(array, leftIndex, rightIndex, pivotIndex, compare)
166 if (k === pivotIndex) {
168 } else if (k < pivotIndex) {
169 return selectRecursion(array, k, leftIndex, pivotIndex - 1, compare)
171 return selectRecursion(array, k, pivotIndex + 1, rightIndex, k, compare)
180 function quickSelectLoop (tasksMap) {
181 const tasksArray = Array.from(tasksMap)
183 return selectLoop(tasksArray, 0, 0, tasksArray.length - 1, (a, b) => {
193 function quickSelectLoopRandomPivot (tasksMap) {
194 const tasksArray = Array.from(tasksMap)
200 tasksArray.length - 1,
204 randomPivotIndexSelect
213 function quickSelectRecursion (tasksMap) {
214 const tasksArray = Array.from(tasksMap)
216 return selectRecursion(tasksArray, 0, 0, tasksArray.length - 1, (a, b) => {
226 function quickSelectRecursionRandomPivot (tasksMap) {
227 const tasksArray = Array.from(tasksMap)
229 return selectRecursion(
233 tasksArray.length - 1,
237 randomPivotIndexSelect
241 group('Least used worker tasks distribution', () => {
242 bench('Loop select', () => {
245 bench('Array sort select', () => {
246 arraySortSelect(tasksMap)
248 bench('Quick select loop', () => {
249 quickSelectLoop(tasksMap)
251 bench('Quick select loop with random pivot', () => {
252 quickSelectLoopRandomPivot(tasksMap)
254 bench('Quick select recursion', () => {
255 quickSelectRecursion(tasksMap)
257 bench('Quick select recursion with random pivot', () => {
258 quickSelectRecursionRandomPivot(tasksMap)
262 await run({ units: true })