簡體   English   中英

Kotlin:如何異步等待一系列相同的方法?

[英]Kotlin: How to async await a list of identical methods?

我有幾百個Java類實例都需要完成他們的.calculate()方法或在10分鍾內死掉。 他們會占用CPU和內存,所以我想一次只允許5(線程?)。 我相信我很接近,但是來自Java背景我還不熟悉kotlin協同程序(vs java ExecutorServices)來進行編譯。

// ...my logic to create a stream of identical class type instances 
// that all have a vanilla blocking .calculate():Double method...
// which I now want to (maybe?) map to Jobs

listOf(MyClass(1), MyClass(2), MyClass(1000))
.map {
  launch(CommonPool) {
    val errorRate: Double? = it?.calculate()
    println("${it?.javaClass?.simpleName}  $errorRate") // desired output
    errorRate
  }
}
.collect(Collectors.toList<Job>())

jobs.forEach {
    println(it.join())
}

然后我想我需要用非阻塞計算包裝計算? 或阻止,但超時有限? 那個“runBlocking”應該在那嗎? 在上面的代碼中作為lambda更好嗎?

fun MyClass.calculateTimeLimited(): Double = runBlocking {
  withTimeout(TIMEOUT) {
    this.calculate() // <-- doesn't compile! "this" is "CoroutineScope"

我不知道你是否知道但有這個偉大的文件: coroutines通過例子 我鏈接了有關取消和超時的特定部分。 以下是我對你的問題的實現:

import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.newSingleThreadContext
import java.util.*
import kotlin.system.measureNanoTime

internal val random = Random()

fun createRandArray(n: Long): Array<Int> {
    return createRandTArray(n).toTypedArray()
}

fun createRandTArray(n: Long): IntArray {
    return random.ints(n, 0, n.toInt()).toArray()
}

var size: Long = 1_000_000
var nRepeats: Int = 11
var nDrops: Int = 1

fun <T> benchmark(name: String,
                  buildSortable: (Long) -> T,
                  sort: (T) -> Any) {
    val arrays = List(nRepeats) { buildSortable(size) }
    val timesMS = arrays.map { measureNanoTime { sort(it) } / 1_000_000 }.drop(nDrops) // for JVM optimization warmup
    // println(timesMS)
    println("[$name] Average sort time for array of size $size: ${timesMS.average() } ms")
}

fun main(args: Array<String>) {
    size = 1_000_000
    nRepeats = 6

    benchmark("Array<Int>",
            buildSortable = { size -> createRandTArray(size).toTypedArray() },
            sort = ::mergeSort)

    benchmark("ListLike Array<Int>",
            buildSortable = { size -> SortingArray(createRandTArray(size).toTypedArray()) },
            sort = { array -> mergeSortLL(array) })  // oddly ::mergeSortLL is refused

    benchmark("ListLike IntArray",
            buildSortable = { size -> createRandTArray(size).asComparableList() },
            sort = { array -> mergeSortLL(array) })  // oddly ::mergeSortLL is refused

    benchmark("IntArray",
            buildSortable = { size -> createRandTArray(size) },
            sort = ::mergeSortIA)

    benchmark("IntArray multi-thread (CommonPool) with many array copies",
            buildSortable = { size -> createRandTArray(size) },
            sort = { mergeSortCorou(it) })

    val origContext = corouContext
    corouContext = newSingleThreadContext("single thread")
    benchmark("IntArray multi-thread (one thread!) with many array copies",
            buildSortable = { size -> createRandTArray(size) },
            sort = { mergeSortCorou(it) })
    corouContext = origContext

    benchmark("Java int[]",
            buildSortable = { size -> createRandTArray(size) },
            sort = { MergeSorter.sort(it) })
}

我得到了輸出:

 Hit the timeout (CancellationException).
 Out of 100 computations, 45 completed.

您可以使用timeOut值(當前為500毫秒)。 每個作業具有從0到1000毫秒的不同隨機執行時間,因此大約一半的作業在超時之前執行。

但是,您可能更難以針對特定問題實施此操作。 您的計算必須是可取消的 請仔細閱讀我上面鏈接的文件中的取消部分。 基本上你的計算要么必須調用kotlinx.coroutines一個suspend函數(這是我在調用delay所做的),或者使用yieldisActive


編輯 :與取消任何工作的評論相關(不可取消/不可暫停):

不,這里沒有魔力。 無論您使用何種框架,使計算真正可取消都非常困難。 眾所周知,Java有Thread.stop() ,它似乎做了你想要的,但已被棄用

我嘗試使用協程來解決在超時后停止提交新作業的簡單問題,但是在超時之前啟動的作業可以遠遠超出超時而不會被取消/中斷。 我花了一些時間在它上面,找不到一個簡單的協程解決方案。 它可以使用標准的Java並發結構來完成。

我的看法(抱歉無法測試我的機器):

val results = streamOfInstances.asSeqence().map {
    async(CommonPool) {
        val errorRate: Double? = it?.calculate()
        println("${it?.javaClass?.simpleName}  $errorRate")
        errorRate
    }
}

runBlocking {
    results.forEach {
        println(it.await())
    }
}  

與您的代碼的主要區別:

  • 因為我正在收集結果,所以我使用async而不是launch
  • 阻塞操作( join()await() )在runBlocking{}
  • 我使用的是Kotlin的map ,而不是JDK8 API

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM