Что происходит при использовании основного потока диспетчера v / s в Android

#android #multithreading #kotlin #kotlin-coroutines

#Android #многопоточность #kotlin #kotlin-сопрограммы

Вопрос:

В контексте Android, в чем разница между диспетчером и основным потоком.

Насколько я понимаю, ссылаясь на документацию,

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

Будет ли это порождать новый поток или в соответствии с именем журнала DefaultDispatcher-worker-1 будет существовать рабочий, который будет взаимодействовать с пулом потоков, отличным от основного, для обработки блока совместной процедуры или worker сам является совместной процедурой?

 override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val timeInMillis = measureTimeMillis {
            GlobalScope.launch(Dispatchers.Default) {
                Log.d(TAG, "Starting coroutine in thread ${Thread.currentThread().name}")
                val answer = doNetworkCall()
                withContext(Dispatchers.Main) {
                    Log.d(TAG, "Setting text in thread ${Thread.currentThread().name}")
                }
            }

        }
        Log.d(TAG, "(The operation took $timeInMillis ms)")

    }
 

Ответ №1:

Диспетчер — это, по сути, пул потоков. При использовании launch(Dispatchers.Default) будет получен поток, используемый для запуска кода в сопрограмме Dispatchers.Default . Каждый раз, когда в сопрограмме происходит вызов функции приостановки, когда сопрограмма возобновляется после этого вызова, она может возобновляться в другом экземпляре потока, поступающем из того же Dispatchers.Default пула потоков.

"DefaultDispatcher-worker-1" это имя буквального Thread экземпляра, который был получен из Dispatcher.Default пула.

withContext сам по себе является вызовом функции приостановки, поэтому любой код после withContext блока также будет возобновлен в каком-либо потоке Dispatchers.Default . (В вашем примере его нет).

Код внутри withContext(Dispatchers.Main) будет выполняться в потоке из Dispatchers.Main .

Dispatchers.Main это специальный диспетчер, который имеет только один поток, и этот поток является тем же основным потоком, который используется ОС.

Вам редко когда-либо нужно использовать GlobalScope , и это не рекомендуется, потому что это не позволяет легко управлять жизненными циклами сопрограмм. Если вы используете lifecycleScope вместо этого, ваши сопрограммы будут автоматически отменены при завершении соответствующего действия или фрагмента. Обычно это то, что вам нужно, потому что действие или фрагмент не должны продолжать выполнять работу после его завершения.

Обычно на Android большинство сопрограмм должны запускаться из lifecycleScope или viewModelScope и не должны указывать диспетчера, поскольку эти области по умолчанию используют Dispatchers.Main то, что вы обычно хотите. (На самом деле они используют другой вызываемый диспетчер Dispatchers.Main.immediate , который также использует основной поток, но также может немедленно запускать первую часть сопрограммы, не откладывая до следующего кадра цикла основного потока. Не то различие, о котором вам нужно беспокоиться.) Вы можете обернуть части своей сопрограммы, в которые нужны другие диспетчеры withContext . Вам не нужно этого делать, если вы вызываете только функции приостановки. По соглашению, функции должны приостанавливаться для внутреннего делегирования конкретному диспетчеру, если им это необходимо.

Исключением из приведенного выше пункта может быть, если вы запускаете сопрограмму, viewModelScope которая выполняет некоторую блокирующую работу и никогда не затрагивает ничего, что доступно только для основного потока. Затем вы можете пропустить withContext и явно указать диспетчера с launch помощью .

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

1. Просто небольшая деталь, но области viewmodel и lifecycle на самом деле поддерживаются Dispatchers.Main.immediate как средство дополнительной оптимизации.

2. Правда, было бы неточно говорить, что они используют Main, но это немного сбивает с толку новичка. Я попытаюсь уточнить.

3. Очень, хорошо объяснено. Не могли бы вы помочь мне с какой-либо ссылкой, которая обеспечивает визуализацию того, как сопрограммы ведут себя с пулом потоков?

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