Насколько «легковесны» сопрограммы для реальной разработки Android? - PullRequest
2 голосов
/ 07 мая 2020

Когда вы начинаете изучать Kotlin сопрограмм, одним из первых примеров, которые вы видите, является то, что можно запустить сотни тысяч сопрограмм, но столкнуться с исключениями OutOfMemory при попытке сделать то же самое с потоками.

Хотя этот пример «крутой», я не думаю, что он полезен и даже немного вводит в заблуждение для разработки Android приложений в реальном мире. Конечно, вы можете запустить сотни тысяч сопрограмм, которые ничего не делают, кроме delay(), но на самом деле вы либо запускаете сопрограммы, которые выполняют какие-то операции ввода-вывода, либо какие-то вычисления.

Если вы, например, запускаете сотни тысяч сопрограмм, и каждая из них выполняет сетевой запрос с помощью Retrofit, это будет не более легким, чем использование Retrofit традиционно без Coroutines, потому что okhttp все еще блокирует поток для каждого запрос.

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

Верно ли мое предположение, что без наличия неблокирующих библиотек ввода-вывода мое приложение не станет более эффективным или «легким» просто с помощью сопрограмм, или я чего-то упускаю?

Ответы [ 2 ]

3 голосов
/ 07 мая 2020

Конечно, вы можете запустить сотни тысяч сопрограмм, которые ничего не делают, кроме delay (), но на самом деле вы либо запускаете сопрограммы, которые выполняют какие-то операции ввода-вывода, либо какие-то вычисления.

Не обязательно. Сопрограммы также могут быть полезны для реорганизации других типов кода, таких как работа с представлениями .

Если вы, например, запускаете сотни тысяч сопрограмм, и каждая выполняет сетевой запрос с Retrofit, он не будет более легким, чем использование Retrofit традиционно без Coroutines, потому что okhttp по-прежнему блокирует поток для каждого запроса.

Я предполагаю, что вы пытаетесь сказать, что OkHttp использует пул потоков. Это определенно так.

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

Это сценарий OutOfMemoryError из исходного абзаца, если вы создаете отдельные потоки для каждого вычисления.

Диспетчеры сопрограмм основаны на пулах потоков. Таковы планировщики Rx Java. Как и AsyncTask, если на то пошло. В конце концов, сценарий "сотни тысяч сопрограмм" сравнивает неиспользование пулов потоков с использованием пулов потоков. Так что да, сравнение «сотен тысяч сопрограмм» не примечательно, потому что есть и другие способы использования пулов потоков.

0 голосов
/ 07 мая 2020

Вы частично правы, запрос открытия нескольких блокирующих IO будет помещен в очередь в Dispatchers.IO , и они будут выполняться последовательно, если максимальное количество запросов превышает 64 (максимальное количество потоков на IO Dispatcher), то есть один за другим, поскольку потоки будут освобождены.

Coroutines не magi c, они просто конвертируют обратные вызовы в последовательный код через Continuation , который за кулисами работает как обработчик обратного вызова.

Сопрограммы в реальных приложениях обычно получают выгоду от простоты изменения потоков, холодного потока, каналов, при этом приостановленные значения получения сопрограмм по существу не занимают поток пока он не будет возобновлен.

В то время как Rx Java делает то же самое, сопрограммы тестируются, чтобы потреблять меньше памяти и требуется значительно меньше времени для выполнения проверьте тесты здесь .

Вы также можете использовать сопрограммы, чтобы сделать возможной глубокую рекурсию, используя кучу памяти i Вместо стека см. реализацию глубокой рекурсии, выполненную Романом Элизаровым с использованием сопрограмм , разве они не достаточно легкие?

...