【问题标题】:How does concurrent modification work with coroutines?并发修改如何与协程一起工作?
【发布时间】:2021-10-28 14:49:53
【问题描述】:

我正在阅读这个coroutines 动手教程Coroutines-Channels。所以有这个任务是使用channels同时获取贡献者并显示中间进度,参见Here

以下是建议解决方案的sn-p

suspend fun loadContributorsChannels(
service: GitHubService,
req: RequestData,
updateResults: suspend (List<User>, completed: Boolean) -> Unit) = coroutineScope {

........
.........
val channel = Channel<List<User>>()
for (repo in repos) {
    launch {
        val users = service.getRepoContributors(req.org, repo.name) // suspend function
            .also { logUsers(repo, it) }
            .bodyList()
        channel.send(users) // suspend function
    }
}
var allUsers = emptyList<User>()
repeat(repos.size) {
    val users = channel.receive()  // suspend function
    allUsers = (allUsers + users).aggregate()
    updateResults(allUsers, it == repos.lastIndex) // suspend function
}
}

函数loadContributorsChannels() 在使用Default dispatcher.See herecoroutine 内调用。我有 2 个问题。

  1. 在上面的 sn-p 中,allUsers 被同时修改,因为我们已经在使用 Default dispatchercoroutine 中?

  2. 如果我像下面这样更改代码序列,为什么会得到不正确的结果?上面的代码和下面的sn-p有什么区别?

    val contributorsChannel = Channel<List<User>>()
    var contributors = emptyList<User>()
    
    for(repo in repos) { 
        launch {
            val contributorsPerRepo = service
                .getRepoContributors(req.org, repo.name) // suspend function
                .also { logUsers(repo, it) }
                .bodyList()
    
            contributors = (contributors + contributorsPerRepo).aggregate()
            contributorsChannel.send(contributors)  // suspend function
        }
    }
    
    repeat(repos.size) {
        updateResults(contributorsChannel.receive(), it == repos.lastIndex) // suspend functions
    }
    

这是因为并发修改还是我遗漏了什么?

【问题讨论】:

    标签: kotlin concurrency kotlin-coroutines kotlinx.coroutines.channels


    【解决方案1】:

    在原始代码中,顶层协程是唯一使用allUsers的协程。这是它的本地状态。

    在您的代码中,contributors 是一个由所有协程共享并同时更新的变量。

    原始代码正确地将 Channel 作为一种同步机制,将所有并发计算扇入到一个协程中,该协程收集结果并使用它们。

    【讨论】:

    • 所以基本上如果一个变量是单个协程的本地变量,它就不能同时修改?如果是这种情况,那么每个协程都是单线程的?即在启动或任何其他创建协程的函数中,只有一个线程可以更新和处理东西?
    • 局部变量并不能保证它的引用对象仅在单个协程中使用。但是,如果您分析帖子中的代码,您会发现它确实仅由顶级协程使用。这特别容易看到,因为它是在启动子协程之后声明的。一个协程的代码是严格按顺序执行的,不管是不是在同一个线程上执行。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多