Как стать автором
Обновить

Современный подход к конкурентности в Android: корутины в Kotlin

Время на прочтение10 мин
Количество просмотров25K
Всего голосов 14: ↑11 и ↓3+8
Комментарии29

Комментарии 29

>> Причем, пока getImage выполняется в выделенном пуле потоков IO, главный поток свободен и может взяться за любую другую задачу!

Ну бред же.

Этот «главный поток» есть недоделанное детище ведро-архитекторов. Все остальные о таком чуде просто не знают (ибо вредные вещи им просто не нужны).

На самом деле поток исполнения блокируется до получения результата. А как там при этом перераспределяются потоки операционной системы — это уже второстепенно. И даже скорее вредно отделять потоки оси от порождаемых виртуальных потоков исполнения кода, ибо всем новичкам будет казаться, что они написали «всё правильно», а на самом деле они видят виртуальную картинку, которую сочинители котлина вынуждены были сочинить из-за убогости ведра, под которое всё же приходится писать (ибо широко распространённое поделие).

В общем — тупо прячем под ковёр гнилые потроха ведроида с его дичайшей асинхронностью и смертью всего на свете из-за лени архитекторов (не захотели под UI выделить отдельный поток).

"Главный поток" — это общая черта любых платформ GUI, а не только Андроида… Как минимум, он присутствует в WINAPI, XLib, WinForms (как следствие WINAPI), WPF, AWT, Qt...

>> это общая черта любых платформ GUI

Внимательно читаем о том, что такое windows, а потом смотрим на приведённый список аббревиатур и… В общем — не надо звонить, не обладая информацией. Затем читаем про систему X Window. Ну и доказываем, как же она подходит под «это общая черта любых платформ GUI».
А каких ещё примеров не хватает? Или вам здесь нужно статью из википедии скопировать?

Процитируйте ключевое на что вы ссылаетесь.
Бегло я не увидел на википедии ничего про потоки.


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


Замечу, что кроме Windows, Android, есть еще iOS/MacOS.

>> сколько не видел туториалов по иксам, там так же идет цикл событий

Читайте обзорную архитектуру. Иксы — это сервер. Он может быть вообще на другой стороне земли. Пояснять далее, почему на другой стороне земли будет отдельный поток?

А причем тут сервер, к клиенту?

Да, здесь всё безнадёжно…

Примеров GUI платформ, где не используется цикл событий в выделенном под него потоке.

Иксы

Сервер иксов да, а клиент?


Вы сейчас сравниваете внутреннюю кухню сервера иксов с тем как работает клиент.
Апельсины с помидорами не очень сравниваются.

Всё со всем можно сравнить. И иксы отлично вписываются в данную тему. Но некоторые почему-то считают, что можно кодить только в одном единственном стиле, когда один глупый программист может повесить всю систему.

О какой "всей системе" речь? "Главный поток" в Андроиде свой собственный для каждого приложения. И повесить глупый программист может только свою собственную программу.

На самом деле поток исполнения блокируется до получения результата.

Он действительно свободен. иначе бы у вас интерфейс завис.
По сути тот код передает исполнение в поток из пула Dispatchers.IO.
Потом управление передается в Dispatchers.Main, этот диспатчер по сути оберка над runOnUiThread процитированным выше.
Все довольно просто.

Кто свободен? Читайте внимательно википедию про «текущий поток исполнения».

Интерфейс виснет от кривого архитектурного решения в ведроиде — UI ждёт, пока неграмотный программист закончит выполнять неэффективно написанную процедуру.

Читайте внимательно код, и что в каком потоке выполняется.


Отсылок на википедию от вас уже достаточно.
А по делу, как не было, так и нет.
одни нападки.

Интересно, что Издательский дом предпочитает изобретать свою терминологию «корутины» вместо устоявшийся "Сопрограммы" :) Боюсь покупать книги такого издательства с необычными терминами — куплю и ничего не пойму.
«Корутинами» их называют создатели языка.
Всё-таки речь идёт про Kotlin. А в сообществе Kotlin слово «корутины» вполне общепринято и встречается чаще, чем «сопрограммы».
Спасибо за ответы. Но ведь каждое сообщество хочет расширяться, хочет чтобы его ЯП стал еще более популярным. А каждый дублирующий термин может создаь проблему для понимания новичком в этом сообществе. В статье при первом появлении такого термина можно написать «корутины (сопрограммы)».
С наилучшими пожеланиями сообществу Kotlin. (Я совершенно искренне).
А вот у меня такой вопрос: вот есть код из статьи:
launch(Dispatchers.Main) {
    val image = withContext(Dispatchers.IO) { getImage() } // контекст IO
    imageView.setImageBitmap(image) // контекст Main
}


Почему для I/O операций необходимо указывать свой контекст? Разве такой код в Android не будет работать/что-то заблокирует?
launch(Dispatchers.Main) {
    val image = getImage() // контекст Main, но это I/O операция
    imageView.setImageBitmap(image) // контекст Main
}


Если getImage() — это метод асинхронного ввода-вывода, разве он не приостановится при выполнении чтения как любая другая асинхронная функция в контексте main? Или это какой-то задел для мультиплатформы или типа того?

Так можно делать, чтобы ограничить число параллельных блокирующих IO операций.


Иначе:


  • Блокирующие операции могут остановить один из общих потоков (т.е. приложение не сможет выполнить простую операцию просто потому, что все потоки ждут, или другими словами — процессор свободен, однако программа не может его использовать). Следовательно — все блокирующие вещи должны быть отдельно.
  • Много IO операций с диском всё равно не смогут выполняться параллельно (дисков-то не так много), значит желательно ограничить параллелизм, чтобы:
    • Соседние операции не мешали друг другу
    • Не создавать много потоков, каждый из которых кушает около 2 Мб (для стандартной Java).

Следовательно, всё блокирующее IO взаимодействие лучше выделить в отдельный пул потоков — Dispatchers.IO


Аналогичная идея есть у .Net с SynchronizationContext.

Следовательно, всё блокирующее IO взаимодействие лучше выделить в отдельный пул потоков — Dispatchers.IO

В этом собственно и был вопрос: а стоит ли метод асинхронного ввода-вывода исполнять в контексте "блокирующего IO взаимодействия"?

В теории, блокирующие I/O операции вообще не должны использоваться, и вместо них необходимо использовать их неблокирующие аналоги. А для операций, которых не имеют таких аналогов (не приходит ничего на ум) — использовать Dispatcher.IO.
Хотя вот тоже спорно — стоило ли вообще делать отдельный диспетчер для ввода-вывода, если Default справляется точно так же? Только ради ограничения по количеству параллельно выполняемых операций? Но в Default по идее также должно стоять такое же ограничение по количеству параллельно выполняющихся блокирующих потоков…
Авторы языка решили, что Dispatcher.IO почему-то удобнее именно для IO, хотя Default работает полностью идентично. Причина такого решения абсолютно непонятна. Точнее — авторы не захотели её пояснять в доках по API.

В целом имеем полное копирование истории с ведроидом — такие же неполноценные доки без пояснения выбранных архитекторами концепций.
Да, планируем
Зарегистрируйтесь на Хабре, чтобы оставить комментарий