Comments 12
Спасибо большое за статью и исходники, но кажется что чего-то не хватает. Всё-таки самых сочных тем про коррутины не раскрыто. У вас всё выглядит как просто некий околосинхронный код, который выполняется с помощью модного синтаксиса где-то там на каких-то диспатчерах и хэндлерах.
Но на самом же деле коррутины можно использовать как миллионы микропотоков через await, обернутых в list, которые в IO пуле могут делать работу не блокируя UI. И дождаться всех можно с помощью awaitAll - это на мой взгляд очень важная фича, которая и подчеркивает легковесность и одновременное выполнение кода, которые дарят коррутины.
Следует всё равно помнить, что корутины по большей части это синтаксический сахар. Чудес не бывает и никакие корутины за вас по-настоящему асинхронный ввод/вывод в JVM не сделают – в лучшем случае удобно скроют синхронную работу в отдельном пуле потоков. Полноценной асинхронной работы IO без блокировок можно добиться только через Selectors.
Если вдаваться в "подкапотную" работу многих инструментов, то, как вы и сказали, чудес не бывает и все в итоге сведётся к распределении работы среди ядер вашего железа. Корутины, действительно, скрывают свою синхронную работу среди потоков, тем самым и добиваясь эффекта асинхронности, который и нужен разработчику
Насчёт Selector, честно говоря, слышу впервые, и был бы благодарен, если бы вы поделились материалом для работы с ним. В документации (https://kotlinlang.org/api/latest/jvm/stdlib/kotlinx.cinterop/-obj-c-factory/selector.html) страница на данный момент ещё не заполнена, но, думаю, мне и другим читателям было бы интересно изучить этот инструмент
https://www.baeldung.com/java-nio-selector
Это интерфейс JVM который обеспечивает доступ к системному вызову epoll в ядро Линукс. Или kqueue в BSD системах. Или аналогичный ему в windows.
Это такой механизм который позволяет сказать ядру OS, что мы ожидаем появление данных (или возможность записи данных) сразу в нескольких file handlers (сетевые сокеты, файлы, whatever). Это позволяет работать в один поток с сотнями и даже тысячами соединений ввода/вывода.
Других альтернатив по-настоящему асинхронной работы с файлами или сетью просто нет.
Правильно ли я понимаю, что корутины это аналог async/await в C#?
Есть какое отличие? async в шарпах завезли еще в прошлом веке, а корутины только последние несколько лет слышно
Спасибо за содержательный материал. Очень логичное и легкое изложение. Есть небольшая ошибка, наверное опечатка) В рис. "Отмена вложенных корутин" второй уровень должен быть Job, а не SupervisorJob как указано. Именно поэтому происходит отмена.
Стоит отметить, что отмена происходит не мгновенно: мы как бы говорим котлину, что нужно отменить это джобу, а он уже при первой возможности этим займётся.
Никакой магии нет, котлин сам ничем не будет заниматься)) Ваш код в первом примере отмены будет правильно выполняться при использовании функции delay в родительской job'е. Если поставить вместо неё какое-то вычисление, например, факториал большого числа, то корутина не отменится пока не закончит свое выполнение. Функция cancel просто ставит флаг isActive в состояние false,и если не обрабатывать в своей функции этот флаг и не выбрасывать CancelationExeption, то функция продолжит своё выполнение до конца. В delay всё это происходит под капотом.
Раздел №11 Способы обработок ошибок в корутинах - описан плохо.
1. Как вы вообще получаете сообщение "job2 end"
и "job3 end"
если job1
выбрасывает исключение и ваша программа падает по ошибке?
2. "в данном случае вложенные launch - это дочерние корутины job1" - может они дочерние для просто job?
Вообще тема обработки ошибок в корутинах более обширна. На Хабре уже есть ряд подробных и хороший статей. Вам следует взять информацию хотя бы оттуда.
Kotlin Coroutines. От А до Я