Concurrency 协同程序:列表中的延迟操作按顺序运行。
我有一个执行下载的参数列表。 我将该列表中的元素映射到执行下载的Concurrency 协同程序:列表中的延迟操作按顺序运行。,concurrency,kotlin,coroutine,kotlinx.coroutines,Concurrency,Kotlin,Coroutine,Kotlinx.coroutines,我有一个执行下载的参数列表。 我将该列表中的元素映射到执行下载的延迟;然后,forEach元素,我调用wait,但显然下载是按顺序执行的 这是我的职责: suspend fun syncFiles() = coroutineScope { remoteRepository.requiredFiles() .filter { localRepository.needToDownload( it.name, it.md5 ) } .map { async {
延迟;然后,forEach
元素,我调用wait
,但显然下载是按顺序执行的
这是我的职责:
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 )
}
这是我的结果:预期介于:和之间,但是是:
我觉得很奇怪,因为这两个虚拟测试正确完成了,可能我遗漏了什么(?)
问题出在mockk
如果您查看coAnswer
函数的代码,您会发现(API.kt+InternalPlatformDsl.kt):
如您所见,coAnswer
是一个非挂起函数,它与runBlocking
启动一个新的协同程序
让我们看一个例子:
val mock = mockk<Downloader> {
coEvery {
this@mockk.download()
} coAnswers {
delay(1000)
}
}
val a = async {
mock.download()
}
val mock=mock{
科弗利{
this@mockk.download()
}共同回答者{
延迟(1000)
}
}
val a=异步{
mock.download()
}
当mock
执行coAnswer
-块(delay()
)时,它启动一个人工协同路由作用域,执行给定的块并等待(阻塞当前线程:runBlocking
),直到该块完成。因此,应答块仅在延迟(1000)
完成后返回
表示从coAnswer运行的所有协程都是按顺序执行的。如果作业阻止整个线程,例如阻止整个线程执行的IO绑定任务,从而阻止该线程上的所有其他协程,则可能会发生这种情况。如果您使用的是Kotlin JVM,请尝试调用async(IO){}
在IO调度程序下运行couroutine,以便couroutine环境现在知道该作业将阻塞整个线程并相应地进行操作
在这里查看其他调度员:您的代码看起来正确。您确定您的下载程序同时运行并且有多个连接吗?另一个原因可能是您的localRepository
,可能它只按顺序运行?一切都是模拟的,downloader只在延迟1秒后返回any(),首先怀疑的是模拟实现。也许它会懒洋洋地启动,只在你调用wait时才执行延迟,嗯,那会很奇怪是的,但我认为这是正常的;但是执行的总时间应该是一秒多一点,因为它们几乎可以同时开始。我错了吗?我的测试用例是错误的,在这种情况下你是对的:-)但问题仍然是一样的。我将改变我的答案。如果你仍然使用代码,请你尝试measureTimeMillis{a.await();b.await();c.await()}
?我的电脑在我的旅行包里,我会在2小时后醒来,我无法入睡,我只是改变了答案。希望这个解释足够好。老实说,不是真的
infix fun coAnswers(answer: suspend MockKAnswerScope<T, B>.(Call) -> T) = answers {
InternalPlatformDsl.runCoroutine {
answer(it)
}
}
actual fun <T> runCoroutine(block: suspend () -> T): T {
return runBlocking {
block()
}
}
val mock = mockk<Downloader> {
coEvery {
this@mockk.download()
} coAnswers {
delay(1000)
}
}
val a = async {
mock.download()
}