Как параллельная модификация работает с сопрограммами?

Я прохожу через это coroutinesпрактическое руководство Coroutines-Channels. Итак, есть задача одновременного получения участников и одновременного отображения промежуточного прогресса с помощью channels, См. Здесь

Ниже представлен фрагмент предлагаемого решения.

      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()вызывается внутри a, который использует.Смотрите здесь . У меня 2 вопроса.

  1. В приведенном выше фрагменте allUsers модифицируются одновременно, так как мы уже находимся внутри coroutine который использует Default dispatcher?

  2. Если я изменю последовательность кода, как показано ниже, почему я получаю неверные результаты? Чем код выше отличается от фрагмента ниже?

            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
    }
    

Это из-за одновременной модификации или мне чего-то не хватает?

1 ответ

В исходном коде только сопрограмма верхнего уровня использует allUsers. Это его местное государство.

В вашем коде contributors - это переменная, совместно используемая всеми сопрограммами и одновременно обновляемая.

Исходный код правильно применяет канал в качестве механизма синхронизации для объединения всех параллельных вычислений в одну сопрограмму, которая собирает результаты и использует их.

Другие вопросы по тегам