我有几百个Java类实例都需要完成他们的.calculate()方法或者在10分钟内死掉。他们会占用CPU和内存,所以我想一次只允许5(线程?)。我相信我很接近,但是来自Java背景我还不熟悉kotlin协同程序(vs java ExecutorServices)来进行编译。
fun MyClass.calculateTimeLimited(): Double = runBlocking {
withTimeout(TIMEOUT) {
this.calculate() // <-- doesn't compile! "this" is "CoroutineScope"
然后我想我需要用非阻塞计算来包装计算?或阻止,但超时有限?应该&#34; runBlocking&#34;在那儿?在上面的代码中作为lambda更好吗?
lapply
答案 0 :(得分:3)
我不知道您是否知道,但有一个很棒的文件:coroutines by example。我链接了有关取消和超时的特定部分。以下是我对您的问题的实施:
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毫秒的不同随机执行时间,因此大约一半的作业在超时之前执行。
但是,您可能更难以针对特定问题实施此操作。您的计算必须可取消。请仔细阅读我上面链接的文件中的取消部分。基本上你的计算要么必须调用suspend
中的一个kotlinx.coroutines
函数(这是我打电话delay
后我做的),或者使用yield
或{{1} }。
编辑:与取消任何作业的评论相关(不可取消/不可暂停):
不,这里没有魔力。无论您使用何种框架,使计算真正可取消都非常困难。众所周知,Java有isActive
,它看起来像你想要的那样,但是deprecated。
我尝试使用协程来解决在超时后停止提交新作业的简单问题,但是在超时之前启动的作业可以远远超出超时而不会被取消/中断。我花了一些时间在它上面,找不到一个简单的协程解决方案。它可以使用标准的Java并发结构来完成。
答案 1 :(得分:2)
我的看法(抱歉无法在我的机器上测试):
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