Как параллельная модификация работает с сопрограммами?
Я прохожу через это
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 вопроса.
В приведенном выше фрагменте
allUsers
модифицируются одновременно, так как мы уже находимся внутриcoroutine
который используетDefault dispatcher
?Если я изменю последовательность кода, как показано ниже, почему я получаю неверные результаты? Чем код выше отличается от фрагмента ниже?
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
- это переменная, совместно используемая всеми сопрограммами и одновременно обновляемая.
Исходный код правильно применяет канал в качестве механизма синхронизации для объединения всех параллельных вычислений в одну сопрограмму, которая собирает результаты и использует их.