Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Parallel processing Kotlin集合上的并行操作?_Parallel Processing_Kotlin - Fatal编程技术网

Parallel processing Kotlin集合上的并行操作?

Parallel processing Kotlin集合上的并行操作?,parallel-processing,kotlin,Parallel Processing,Kotlin,在Scala中,您可以使用以下工具轻松地执行并行映射、forEach等操作: collection.par.map(..) Kotlin是否有一个等价物?目前没有。与Scala相比,官方Kotlin提到: 以后可能添加到Kotlin的内容: 平行集合 Kotlin标准库不支持并行操作。但是,由于Kotlin使用标准Java集合类,因此也可以使用Java8流API对Kotlin集合执行并行操作 e、 g。 Kotlin的stdlib中还没有官方支持,但是您可以定义一个模拟par.map:

在Scala中,您可以使用以下工具轻松地执行并行映射、forEach等操作:

collection.par.map(..)

Kotlin是否有一个等价物?

目前没有。与Scala相比,官方Kotlin提到:

以后可能添加到Kotlin的内容:

  • 平行集合

Kotlin标准库不支持并行操作。但是,由于Kotlin使用标准Java集合类,因此也可以使用Java8流API对Kotlin集合执行并行操作

e、 g。


Kotlin的stdlib中还没有官方支持,但是您可以定义一个模拟
par.map

fun <T, R> Iterable<T>.pmap(
          numThreads: Int = Runtime.getRuntime().availableProcessors() - 2, 
          exec: ExecutorService = Executors.newFixedThreadPool(numThreads),
          transform: (T) -> R): List<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<R>(defaultSize))

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

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

    return ArrayList<R>(destination)
}
如果需要,它允许通过提供线程数甚至特定的
java.util.concurrent.Executor
来调整线程。例如

listOf("foo", "bar").pmap(4, transform = { it + "!" })

请注意,这种方法只允许并行化
map
操作,不影响任何下游位。例如,第一个示例中的
过滤器将运行单线程。然而,在许多情况下,仅数据转换(即
map
)需要并行化。此外,将该方法从上面扩展到Kotlin collection API的其他元素也很简单。

从Kotlin 1.1开始,并行操作也可以非常优雅地表示为。以下是列表中的
pmap

fun <A, B>List<A>.pmap(f: suspend (A) -> B): List<B> = runBlocking {
    map { async(CommonPool) { f(it) } }.map { it.await() }
}
fun List.pmap(f:suspend(A)->B):List=runBlocking{
map{async(CommonPool){f(it)}}.map{it.await()}
}

请注意,协同程序仍然是一个实验性的特性。

从1.2版本开始,kotlin添加了一个与JRE8兼容的

因此,异步迭代列表可以如下所示:

fun main(args: Array<String>) {
  val c = listOf("toto", "tata", "tutu")
  c.parallelStream().forEach { println(it) }
}
fun main(args:Array){
val c=列表(“托托”、“塔塔”、“图图”)
c、 parallelStream().forEach{println(it)}
}

Kotlin希望自己的语言习惯化,但不要太过合成,这样乍一看就很难理解

通过协同程序进行并行计算也不例外。他们希望它是简单的,但不是隐式的,使用一些预先构建的方法,允许在需要时进行分支计算

就你而言:

collection.map { 
        async{ produceWith(it) } 
    }
    .forEach { 
        consume(it.await()) 
    }
请注意,要调用
async
await
您需要位于所谓的
上下文中,您不能从非协同路由上下文中挂起调用或启动协同路由。要输入一个,您可以:

  • runBlocking{/*此处的代码*/}
    :它将挂起当前线程,直到lambda返回
  • GlobalScope.launch{}
    :它将并行执行lambda;如果您的
    main
    完成了执行,而您的协同程序没有发生错误,那么最好使用
    runBlocking

希望有帮助:)

此解决方案假定您的项目正在使用协同程序:

implementation( "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.2")
名为
parallelTransform
的函数不保留元素的顺序并返回
,而
parallelMap
函数保留顺序并返回
列表

为多个调用创建线程池:

val numberOfCores = Runtime.getRuntime().availableProcessors()
val executorDispatcher: ExecutorCoroutineDispatcher =
    Executors.newFixedThreadPool(numberOfCores ).asCoroutineDispatcher()
使用该调度器(当不再需要时调用
close()
):

inline fun Iterable.parallelTransform(
调度员:执行调度员,
交叉内联变换:(T)->R
):流量=渠道流量{
val项目:Iterable=this@parallelTransform
val channelFlowScope:ProducerScope=this@channelFlow
发射(调度员){
items.forEach{item->
发射{
channelFlowScope.send(转换(项目))
}
}
}
}
如果不考虑线程池重用(线程池并不便宜),则可以使用以下版本:

inline fun <T, R> Iterable<T>.parallelTransform(
    numberOfThreads: Int,
    crossinline transform: (T) -> R
): Flow<R> = channelFlow {

    val items: Iterable<T> = this@parallelTransform
    val channelFlowScope: ProducerScope<R> = this@channelFlow

    Executors.newFixedThreadPool(numberOfThreads).asCoroutineDispatcher().use { dispatcher ->
        launch( dispatcher ) {
            items.forEach { item ->
                launch {
                    channelFlowScope.send(transform(item))
                }
            }
        }
    }
}
inline fun Iterable.parallelTransform(
numberOfThreads:Int,
交叉内联变换:(T)->R
):流量=渠道流量{
val项目:Iterable=this@parallelTransform
val channelFlowScope:ProducerScope=this@channelFlow
Executors.newFixedThreadPool(numberOfThreads).asCoroutineDispatcher()。使用{dispatcher->
发射(调度员){
items.forEach{item->
发射{
channelFlowScope.send(转换(项目))
}
}
}
}
}
如果需要保留元素顺序的版本:

inline fun <T, R> Iterable<T>.parallelMap(
    dispatcher: ExecutorDispatcher,
    crossinline transform: (T) -> R
): List<R> = runBlocking {

    val items: Iterable<T> = this@parallelMap
    val result = ConcurrentSkipListMap<Int, R>()

    launch(dispatcher) {
        items.withIndex().forEach {(index, item) ->
            launch {
                result[index] = transform(item)
            }
        }
    }

    // ConcurrentSkipListMap is a SortedMap
    // so the values will be in the right order
    result.values.toList()
}
inline fun Iterable.parallelMap(
调度员:执行调度员,
交叉内联变换:(T)->R
):List=runBlocking{
val项目:Iterable=this@parallelMap
val结果=ConcurrentSkipListMap()
发射(调度员){
items.withIndex().forEach{(索引,项)->
发射{
结果[索引]=转换(项目)
}
}
}
//ConcurrentSkipListMap是一个分类地图
//因此,这些值的顺序是正确的
result.values.toList()
}

您可以使用此扩展方法:

suspend fun <A, B> Iterable<A>.pmap(f: suspend (A) -> B): List<B> = coroutineScope {
    map { async { f(it) } }.awaitAll()
}

suspend fun以获取更多信息

我发现另一种非常优雅的方法是这样的,使用库:

导入kotlinx.coroutines.flow.asFlow
暂停乐趣流程(myCollection:Iterable){
myCollection.asFlow()
.map{/*…*/}
.filter{/*…*/}
.collect{/*…执行一些副作用…*/}
}

然而,它确实需要额外的依赖性
kotlinx.coroutines
不在stdlib中。

一些最快的并行集合来自GS集合:。。。您可以从Kotlin使用它(正如任何Java收集框架都可以使用一样)。如何在Kotlin中使用Java8流API?@LordScone,方法与在Java中使用的方法相同。例如:
myCollection.parallelStream().map{…}。filter{…}
仅供参考,parallelStream仅在长列表的情况下建议使用,对于较小的列表,在java world中的不同线程中运行这两个作业将是一种开销。尽可能地坚持合作。我看不出“destination.ad
inline fun <T, R> Iterable<T>.parallelTransform(
    numberOfThreads: Int,
    crossinline transform: (T) -> R
): Flow<R> = channelFlow {

    val items: Iterable<T> = this@parallelTransform
    val channelFlowScope: ProducerScope<R> = this@channelFlow

    Executors.newFixedThreadPool(numberOfThreads).asCoroutineDispatcher().use { dispatcher ->
        launch( dispatcher ) {
            items.forEach { item ->
                launch {
                    channelFlowScope.send(transform(item))
                }
            }
        }
    }
}
inline fun <T, R> Iterable<T>.parallelMap(
    dispatcher: ExecutorDispatcher,
    crossinline transform: (T) -> R
): List<R> = runBlocking {

    val items: Iterable<T> = this@parallelMap
    val result = ConcurrentSkipListMap<Int, R>()

    launch(dispatcher) {
        items.withIndex().forEach {(index, item) ->
            launch {
                result[index] = transform(item)
            }
        }
    }

    // ConcurrentSkipListMap is a SortedMap
    // so the values will be in the right order
    result.values.toList()
}
suspend fun <A, B> Iterable<A>.pmap(f: suspend (A) -> B): List<B> = coroutineScope {
    map { async { f(it) } }.awaitAll()
}