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 arraySortSelect (tasksMap) {
30 const tasksArray = Array.from(tasksMap)
31 return tasksArray.sort((a, b) => {
47 function loopSelect (tasksMap) {
49 let minValue = Number.POSITIVE_INFINITY
50 for (const [key, value] of tasksMap) {
54 if (value < minValue) {
59 return [minKey, minValue]
62 const defaultComparator = (a, b) => {
66 const defaultPivotIndexSelect = (leftIndex, rightIndex) => {
67 return leftIndex + Math.floor((rightIndex - leftIndex) / 2)
70 const randomPivotIndexSelect = (leftIndex, rightIndex) => {
71 return randomInt(leftIndex, rightIndex)
88 compare = defaultComparator
90 const pivotValue = array[pivotIndex]
91 swap(array, pivotIndex, rightIndex)
92 let storeIndex = leftIndex
93 for (let i = leftIndex; i < rightIndex; i++) {
94 if (compare(array[i], pivotValue)) {
95 swap(array, storeIndex, i)
99 swap(array, rightIndex, storeIndex)
108 function quickSelectLoop (tasksMap) {
109 const tasksArray = Array.from(tasksMap)
111 return selectLoop(tasksArray, 0, 0, tasksArray.length - 1, (a, b) => {
121 function quickSelectLoopRandomPivot (tasksMap) {
122 const tasksArray = Array.from(tasksMap)
128 tasksArray.length - 1,
132 randomPivotIndexSelect
141 function quickSelectRecursion (tasksMap) {
142 const tasksArray = Array.from(tasksMap)
144 return selectRecursion(tasksArray, 0, 0, tasksArray.length - 1, (a, b) => {
154 function quickSelectRecursionRandomPivot (tasksMap) {
155 const tasksArray = Array.from(tasksMap)
157 return selectRecursion(
161 tasksArray.length - 1,
165 randomPivotIndexSelect
176 * @param pivotIndexSelect
179 function selectLoop (
184 compare = defaultComparator,
185 pivotIndexSelect = defaultPivotIndexSelect
188 if (leftIndex === rightIndex) return array[leftIndex]
189 let pivotIndex = pivotIndexSelect(leftIndex, rightIndex)
190 pivotIndex = partition(array, leftIndex, rightIndex, pivotIndex, compare)
191 if (k === pivotIndex) {
194 if (k < pivotIndex) {
195 rightIndex = pivotIndex - 1
197 leftIndex = pivotIndex + 1
209 * @param pivotIndexSelect
212 function selectRecursion (
217 compare = defaultComparator,
218 pivotIndexSelect = defaultPivotIndexSelect
220 if (leftIndex === rightIndex) return array[leftIndex]
221 let pivotIndex = pivotIndexSelect(leftIndex, rightIndex)
222 pivotIndex = partition(array, leftIndex, rightIndex, pivotIndex, compare)
223 if (k === pivotIndex) {
226 if (k < pivotIndex) {
227 return selectRecursion(array, k, leftIndex, pivotIndex - 1, compare)
229 return selectRecursion(array, k, pivotIndex + 1, rightIndex, k, compare)
238 function swap (array, index1, index2) {
239 const tmp = array[index1]
240 array[index1] = array[index2]
244 group('Least used worker tasks distribution', () => {
245 bench('Loop select', () => {
248 bench('Array sort select', () => {
249 arraySortSelect(tasksMap)
251 bench('Quick select loop', () => {
252 quickSelectLoop(tasksMap)
254 bench('Quick select loop with random pivot', () => {
255 quickSelectLoopRandomPivot(tasksMap)
257 bench('Quick select recursion', () => {
258 quickSelectRecursion(tasksMap)
260 bench('Quick select recursion with random pivot', () => {
261 quickSelectRecursionRandomPivot(tasksMap)
265 await run({ units: true })