处理大数组的多线程计算

时间:2019-06-21 09:44:05

标签: java multithreading kotlin kotlin-coroutines

我有一个大型数组,需要对该数组的每个元素进行繁重的CPU工作。

基于my similar question,Alexei Kaigorodov先生建议最好的方法是在每个单独的线程上拆分计算的每个数据块。

我使用Kotlin协程实现算法:

suspend fun predictAll(movingVehicles: List<MovingVehicle>): List<MovingVehicle?> {
    val prevTime = Timestamp(Date().time)
    val nextTime = Timestamp(Date().time)
    val ctx = Dispatchers.Default
    val processors = Runtime.getRuntime().availableProcessors()
    val chunks = movingVehicles.chunked(movingVehicles.count() / processors)
    val s = coroutineScope {
        val res = mutableListOf<Deferred<List<MovingVehicle?>>>()
        for (c in chunks) {
            val r = async(ctx) {
                c.map { predictLocation(it, prevTime, nextTime) }
            }
            res.add(r)
        }
        res.awaitAll()
    }
    return s.flatten()
}

private fun predictLocation(
    mv: MovingVehicle,
    prevTime: Timestamp,
    nextTime: Timestamp,
    relevance: Int = 5
): MovingVehicle?

它有效,但是也许有更好的方法吗? 我在寻找ExecutorService,但看起来它比协程需要更多样板代码。

1 个答案:

答案 0 :(得分:2)

这实际上是使用协程的Kotilinic方法。您提交可以同时执行的异步任务,然后等待它们完成。

令人深思。一切都在线程中执行。这意味着协程也将在线程上执行,如果您的任务正在阻塞该线程将被阻塞。协程将不会保存在那里。因此,通常最好的做法是创建一个Threadpool,并且具有最适合应用程序的属性(背压机制,最小/最大线程数等)

现在,在您的情况下,您有cpu绑定的任务,通过拥有大量线程无法获得更高的性能。对于此类任务,Amdahl's_law的实际应用给出-

#threads = #cpu-cores - 1

默认情况下,协程由common pool支持,该线程与上面提到的线程数相同,因此保留默认设置似乎很好。

但是,可能有多个库正在使用该池,并且如果其中任何一个都具有IO阻止任务,则会降低性能。我建议您创建自己的ForkJoinPool并将其用作调度程序

val nOfThreads = Runtime.getRuntime().availableProcessors() - 1;
val ctx = ForkJoinPool( if (nOfThreads == 0) then 1 else nOfThreads).asCoroutineDispatcher()