具有暂停功能fetchData()
。它的作用是在withContext
中启动一些作业,以便仅在作业完成后才返回(即:suspend fun getData(): Boolean
)。
还希望它是否超时,然后从该函数返回false。
问题是当它withTimeoutOrNull(500) { jobs.joinAll() }
超时时,它停留在函数中而没有退出。
日志显示超时,并且在退出函数之前也清楚地指向代码的最后一行:
E/+++: +++ in fetchData() after null = withTimeoutOrNull(500), jobs.sizs: 3
E/+++: +++ --- exit fetchData(), allFresh: false
但是fetchData()
的呼叫者被卡住,无法从fetchData()
返回。
这是呼叫者:
suspend fun caller() {
var allGood = fetchData()
// never return to here
Log.e("+++", "+++ caller(), after allGood: $allGood = fetchData()")
...
}
下面是代码,如果超时,如何取消作业?
suspend fun fetchData(): Boolean = withContext(Dispatchers.IO) {
var allFresh = requestHandlertMap.size > 0
if (!allFresh) {
allFresh
} else {
val handlers = requestHandlertMap.values.toList()
val jobs: List<Deferred<Boolean>> = handlers.map {handler->
async(start = CoroutineStart.LAZY) {
if (isActive) handler.getData() else true
.also {
Log.e("+++", "+++ in fetchData():async{} after handler.getData()")
}
}
}
val result = withTimeoutOrNull(500) { jobs.joinAll() }
Log.e("+++", "+++ in fetchData() after $result = withTimeoutOrNull(500), jobs.size: ${jobs.size} ")
if (result != null) {
allFresh = jobs.all { deferred ->
deferred.await()
}
Log.e("+++", "+++ +++ +++ in fetchData() call onDataReady(), allFresh: $allFresh = deferred.await() ")
onDataReady()
} else {
// how to cancel the jobs ???
//jobs.all { deferred ->
//deferred.cancelChildren()
//}
allFresh = false
}
allFresh
.also {
Log.e("+++", "+++ --- exit fetchData(), allFresh: $allFresh ")
}
}
}
答案 0 :(得分:0)
在阅读/尝试之后,似乎在实现方面遇到了一些问题。
CoroutineStart.LAZY
导致一种奇怪的行为,即async(start = CoroutineStart.LAZY)
按顺序开始(期望它们应该同时开始),以便在超时时卡在函数中(猜测是因为它包装在withContext(Dispatchers.IO)
中,并且并非所有子协程都完成了-如果有人不开始)。删除start = CoroutineStart.LAZY
使其从fun fetchData()
返回
val jobs: List<Deferred<Boolean>> = handlers.map {handler->
async(start = CoroutineStart.LAZY) {
if (isActive) handler.getData() else true
.also {
Log.e("+++", "+++ in fetchData():async{} after handler.getData()")
}
}
}
尚未实现suspend fun getData(): Boolean
cooperate to be cancellable
,这可能导致它仍然停留在函数中,直到所有子项都完成为止,尽管已经发生了超时。
似乎仍然需要调用deferred.cancelChildren()
,否则withTimeoutNotNull()
不会取消它们,不知道为什么,它不应该自动取消作业吗?
所做的更改
private suspend fun fetchData(): Boolean {
var allFresh: Boolean? = requestHandlertMap.size > 0
if (allFresh == true) {
val handlers = requestHandlertMap.values.toList()
val jobs: List<Deferred<Boolean>> = handlers.map {
serviceScope.async(start = CoroutineStart.DEFAULT) { handler -> if (isActive) handler.getData() else false }
}
allFresh = withTimeoutOrNull(3000) {
try {
jobs.awaitAll().all { it }
} catch (ex: Throwable) {
false
}
}
if (allFresh != null) {
onDataReady()
} else {
jobs.map { deferred -> deferred.cancelChildren() }
}
}
return allFresh == true // allFresh = {null, true, false}
}