All Downloads are FREE. Search and download functionalities are using the official Maven repository.

graphics.scenery.utils.ParallelHelpers.kt Maven / Gradle / Ivy

@file:Suppress("unused")

package graphics.scenery.utils

import kotlinx.coroutines.*
import java.util.*
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicInteger
import kotlin.concurrent.thread

/**
 * Maps the function [f] asynchronously on [this], returning the resultant list.
 *
 * Works via Kotlin Coroutines.
 */
fun Iterable.mapAsync(f: suspend (A) -> B): List = runBlocking {
    map { async(Dispatchers.Default) { f(it) } }.map { it.await() }
}

/**
 * Runs the function [f] asynchronously on [this].
 *
 * Works via Kotlin Coroutines.
 */
fun Iterable.forEachAsync(f: suspend (A) -> B) = runBlocking {
    map { async(Dispatchers.Default) { f(it) } }.forEach { it.await() }
}

/**
 * Runs the function [f] indexed asynchronously on [this].
 *
 * Works via Kotlin Coroutines.
 */
fun Iterable.forEachIndexedAsync(f: suspend (Int, A) -> B) = runBlocking {
    val index = AtomicInteger(0)
    map { async(Dispatchers.Default) { f(index.getAndIncrement(), it) } }.forEach { it.await() }
}

/**
 * Maps the function [transform] asynchronously on [this], returning the resultant list.
 * An optional [ExecutorService] may be given via [exec], the number of threads can be limited
 * by setting [numThreads], default number is (availableCores - 2).
 *
 * Works via Executor Services.
 * by Holger Brandl, https://stackoverflow.com/a/35638609
 */
fun  Iterable.mapParallel(
    numThreads: Int = Runtime.getRuntime().availableProcessors() - 2,
    exec: ExecutorService = Executors.newFixedThreadPool(numThreads),
    transform: (T) -> R): List {

    // default size is just an inlined version of kotlin.collections.collectionSizeOrDefault
    val defaultSize = if (this is Collection<*>) this.size else 10
    val destination = Collections.synchronizedList(ArrayList(defaultSize))

    for (item in this) {
        exec.submit { destination.add(transform(item)) }
    }

    exec.shutdown()
    exec.awaitTermination(1, TimeUnit.DAYS)

    return ArrayList(destination)
}

/**
 * Runs the function [transform] asynchronously on [this], returning the resultant list.
 * An optional [ExecutorService] may be given via [exec], the number of threads can be limited
 * by setting [numThreads], default number is (availableCores - 2).
 *
 * Works via Executor Services.
 * derived from Holger Brandl's solution for map, https://stackoverflow.com/a/35638609
 */
fun  Iterable.forEachParallel(
    numThreads: Int = Runtime.getRuntime().availableProcessors() - 2,
    exec: ExecutorService = Executors.newFixedThreadPool(numThreads),
    transform: (T) -> R) {

    // default size is just an inlined version of kotlin.collections.collectionSizeOrDefault
    val defaultSize = if (this is Collection<*>) this.size else 10
    val destination = Collections.synchronizedList(ArrayList(defaultSize))

    for (item in this) {
        exec.submit { destination.add(transform(item)) }
    }

    exec.shutdown()
    exec.awaitTermination(1, TimeUnit.DAYS)
}

/**
 * Parallel forEach implementation for HashMaps.
 *
 * @param[maxThreads] Maximum number of parallel threads
 * @param[action] Lambda containing the action to be executed for each key, value pair.
 */
fun  HashMap.forEachParallel(maxThreads: Int = 5, action: ((K, V) -> Unit)) {
    val iterator = this.asSequence().iterator()
    var threadCount = 0

    while (iterator.hasNext()) {
        val current = iterator.next()

        thread {
            threadCount++
            while (threadCount > maxThreads) {
                Thread.sleep(50)
            }

            action.invoke(current.key, current.value)
            threadCount--
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy