[英]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
所做的),或者使用yield
或isActive
。
編輯 :與取消任何工作的評論相關(不可取消/不可暫停):
不,這里沒有魔力。 無論您使用何種框架,使計算真正可取消都非常困難。 眾所周知,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{}
map
,而不是JDK8 API
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.