【发布时间】:2019-04-13 18:33:11
【问题描述】:
我有一个List 的参数用于执行下载。
我将该列表的元素映射到执行下载的Deferred;然后,列表的forEach 元素,我调用await,但显然下载是按顺序执行的。
这是我的功能:
suspend fun syncFiles() = coroutineScope {
remoteRepository.requiredFiles()
.filter { localRepository.needToDownload( it.name, it.md5 ) }
.map { async { downloader( it ) } }
.forEach { deferredResult ->
when ( val result = deferredResult.await() ) {
is DownloadResult.Layout -> localRepository.storeLayout( result.content )
is DownloadResult.StringR -> localRepository.storeFile( result )
}
}
}
这是我的测试:
private val useCase = SyncUseCaseImpl.Factory(
mockk { // downloader
coEvery { this@mockk.invoke( any() ) } coAnswers { delay(1000 );any() }
},
...
).newInstance()
@Test
fun `syncFiles downloadConcurrently`() = runBlocking {
val requiredFilesCount = useCase.remoteRepository.requiredFiles().size
assert( requiredFilesCount ).isEqualTo( 3 )
val time = measureTimeMillis {
useCase.syncFiles()
}
assert( time ).isBetween( 1000, 1100 )
}
这是我的结果:expected to be between:<1000L> and <1100L> but was:<3081L>
我觉得很奇怪,因为这两个虚拟测试正确完成,也许我遗漏了什么(?)
@Test // OK
fun test() = runBlocking {
val a = async { delay(1000 ) }
val b = async { delay(1000 ) }
val c = async { delay(1000 ) }
val time = measureTimeMillis {
a.await()
b.await()
c.await()
}
assert( time ).isBetween( 1000, 1100 )
}
@Test // OK
fun test() = runBlocking {
val wasteTime: suspend () -> Unit = { delay(1000 ) }
suspend fun wasteTimeConcurrently() = listOf( wasteTime, wasteTime, wasteTime )
.map { async { it() } }
.forEach { it.await() }
val time = measureTimeMillis {
wasteTimeConcurrently()
}
assert( time ).isBetween( 1000, 1100 )
}
【问题讨论】:
-
您的代码看起来正确。您确定您的
downloader同时运行并且有多个连接吗?另一个原因可能是你的localRepository,也许它只按顺序运行? -
一切都被嘲笑了,下载器在延迟 1 秒后返回 any()
-
首先要怀疑的是模拟实现。也许它会懒惰地启动并仅在您调用
await时执行delay。 -
嗯,那会很奇怪????但我不是说不可能,我会调试它,谢谢
标签: concurrency kotlin coroutine kotlinx.coroutines