Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angularjs/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Concurrency 协同程序:列表中的延迟操作按顺序运行。_Concurrency_Kotlin_Coroutine_Kotlinx.coroutines - Fatal编程技术网

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()
}