Когда указывать Dispatchers.xxx для сопрограмм в классах - PullRequest
0 голосов
/ 13 января 2020

Я часто создаю классы, в которых есть функции, содержащие сопрограмму. Не всегда ясно, используется ли функция каким-либо компонентом, связанным с пользовательским интерфейсом, или она выполняет фоновую работу, которая больше ориентирована на ввод-вывод. Вот пример:

fun myFunction() {
    GlobalScope.launch {
       // Do something
    }
}

В этом примере не указано ни Dispatcher.MAIN, ни Dispatchers.IO. Это правильный способ сделать это? Использует ли сопрограмма область действия того, что использует вызывающий клиент? Должен ли я указывать диспетчер только тогда, когда я точно знаю, что мне нужна конкретная область действия c?

Ответы [ 3 ]

1 голос
/ 14 января 2020

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

  • Coroutine завершит свою работу.
  • Само приложение уничтожено.

Использование asyn c или запуск на экземпляре GlobalScope крайне не рекомендуется.

Не указан Dispatcher.MAIN или Dispatchers.IO. Это правильный способ сделать это?

Да, а почему бы и нет? Если работа внутри сопрограммы не связана с UI или IO go для нее.

Должен ли я указывать диспетчер только тогда, когда я точно знаю, что мне нужна конкретная c область действия?

Чтобы ответить на этот вопрос, давайте сначала посмотрим определение launch из документов

 fun CoroutineScope.launch(
     context: CoroutineContext = EmptyCoroutineContext,
     start: CoroutineStart = CoroutineStart.DEFAULT,
     block: suspend CoroutineScope.() -> Unit ): Job (source)

Dispatcher, о котором мы говорим, является своего рода CoroutineContext. Как вы можете видеть из определения, если CoroutineContext не упоминается (что означает, что мы не упомянули также и Dispatcher), то по умолчанию установлено значение EmptyCoroutineContext, которое внутренне использует Dispatchers.Default, и именно об этом говорят документы it,

CoroutineDispatcher по умолчанию, который используется всеми стандартными сборщиками, такими как launch, asyn c, et c, если в их контексте не указан ни диспетчер, ни какой-либо другой ContinuationInterceptor.

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

Так что даже если вы забудете упомянуть Dispatcher, планировщик выберет любое Произведите случайную доступную нить из пула и передайте ей сопрограмму. Но следите за тем, чтобы не начинать какую-либо работу, связанную с UI, без упоминания Диспетчера.

0 голосов
/ 16 января 2020

Прежде всего, вы должны отличить область от контекста и диспетчера .

сопрограммы области действия прежде всего о жизненном цикле сопрограммы и имеет дело с концепцией структурированного параллелизма. Он может иметь диспетчер по умолчанию, который будет логически связан с объектом, для которого вы ie используете жизненный цикл сопрограммы. Например, если вы добавили сопрограмму в действие Android, диспетчером по умолчанию будет UI.

Coroutine context относится к диспетчеру. Контекст должен измениться во время выполнения сопрограммы, как этого требует логика c внутри. Как правило, вы будете использовать withContext для временного переключения диспетчеров во избежание блокировки потока пользовательского интерфейса. Вы не обычно запускаете всю сопрограмму в пуле потоков, если только она не должна выполняться в фоновом потоке (например, без взаимодействия с пользовательским интерфейсом).

Во-вторых, выбор диспетчера должен быть сопоставленным с кодом, который требует определенного c. Это должно происходить внутри функции, которая имеет дело с данной проблемой, такой как выполнение запросов REST или операций с БД. Это еще раз укрепляет практику не выбирать диспетчеров при запуске сопрограммы.

0 голосов
/ 13 января 2020

GlobalScope - это EmptyCoroutineScope, и все сопрограммы, запускаемые с этой областью, похожи на демонстрационные потоки. Они не могут быть отменены и остаются активными до их завершения. Я предлагаю реализовать специфицированную область действия c, не используя GlobalScope, чтобы контролировать все запущенные сопрограммы. GlobalScope использует Dispatchers.Default в качестве диспетчера по умолчанию, и в вашем случае вы всегда создаете сопрограммы в диспетчере по умолчанию.

...