Alexjok
01/09/2019, 11:20 AMovveride fun onMessage(message: Message) = runBlocking {
worker()
}
fun worker(msg: String) = GlobalScope.launch
{
doSomeWork(msg)//какой-то долгий процесс
}
Как лучше написать, чтобы была возможность контролировать количество одновременно работающих worker?r4zzz4k
01/09/2019, 11:34 AMrunBlocking { launch { ... } }
заблокирует текущий поток до конца выполнения корутины, потому такая конструкция не имеет смысла.Alexjok
01/09/2019, 11:50 AMr4zzz4k
01/09/2019, 12:06 PMGlobalScope
разве что не будет самостоятельно дожидаться / отменять корутину в связке с родительским скоупом, потому что его нет. А блокировать будет runBlocking
.
Если ограничить нужно до разумного количества, и есть возможность выделить количество потоков, соответствующее максимальному количеству параллельных задач, то это можно сделать на основании newFixedThreadPoolContext
-- достаточно запустить на нём actor
, по идее. Если потоков должно быть меньше, чем количество параллельных задач -- нужно руками следить за количеством незавершённых задач, опираясь на какой-нибудь AtomicInt
и врапая свой doSomeWork
в инкремент и декремент счётчика.Alexjok
01/09/2019, 12:14 PMfun main(args: Array<String>) = runBlocking {
for (i in 0..10) {
val word = "Hello"
onMessage(word)
}
println("loop is finish now")
delay(3000)
}
fun onMessage(message: String) = GlobalScope.launch {
delay(2000)
println(message)
}
r4zzz4k
01/09/2019, 1:17 PMrunBlocking
в данном случае ничего не делает, потому что GlobalScope.launch
сам не саспендится, а это единственная операция в onMessage
. То есть runBlocking
можно вообще со спокойной душой убрать.
Правда, вы всё ещё, оперируя глобальным скоупом, теряете исключения и возможность сделать graceful shutdown, так как у вас нету конкретного скоупа, в котором запущены все задачи.
Можете конкретную ссылку подкинуть, о чём речь идёт? Там несколько часовых докладов всё-таки.elizarov
01/09/2019, 8:18 PMAlexjok
01/10/2019, 7:13 AMelizarov
01/10/2019, 8:32 AMval locations = Channel<String>(N_WORKERS)
val contents = Channel<String>(N_WORKERS)
Это, заодно, увеличит пропускную способность, так как гарантированно позволить каждому woker-у выслать свой ответ и начать работать над следующим заданием. Но само по себе не гарантирует отсутствие дедлока (а просто сделает его менее вероятным). Надо еще в select
переставить местами блоки — первым обрабатывать contents.onReceive
(всегда забирать ответы если они есть), а только потом (если нет ответов для обработки) делать references.onReceive
.Alexjok
01/10/2019, 9:01 AMelizarov
01/10/2019, 9:03 AMreferences.onReceive
), то легко доказать, что дедлока быть не может.Alexjok
01/10/2019, 9:10 AM