📜  Kotlin协程中的调度程序

📅  最后修改于: 2021-05-08 20:34:19             🧑  作者: Mango

先决条件: Android上的Kotlin协程

众所周知,协程总是在特定的上下文中启动,并且该上下文描述了协程将在哪个线程中启动。通常,我们可以使用GlobalScope来启动协程,而无需将任何参数传递给它,没有指定协程应在其中启动的线程。由于协程可以在任何可用线程中启动,因此此方法并不能为我们提供太多控制,因此无法预测已启动协程的线程。

Kotlin
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
  
        // coroutine launched in GlobalScope
        GlobalScope.launch() {
        Log.i("Inside Global Scope ",Thread.currentThread().name.toString())
            // getting the name of thread in
            // which our coroutine has been launched
        }
  
        Log.i("Main Activity ",Thread.currentThread().name.toString())
    }
}


Kotlin
GlobalScope.launch(Dispatchers.Main) {
       Log.i("Inside Global Scope ",Thread.currentThread().name.toString())
           // getting the name of thread in which 
              // our coroutine has been launched
       }
       Log.i("Main Activity ",Thread.currentThread().name.toString())


Kotlin
GlobalScope.launch(Dispatchers.IO) {
       Log.i("Inside IO dispatcher ",Thread.currentThread().name.toString())
           // getting the name of thread in which
              // our coroutine has been launched
       }
       Log.i("Main Activity ",Thread.currentThread().name.toString())


Kotlin
GlobalScope.launch(Dispatchers.Default) {
        Log.i("Inside Default dispatcher ",Thread.currentThread().name.toString())
            // getting the name of thread in which 
              // our coroutine has been launched
        }
        Log.i("Main Activity ",Thread.currentThread().name.toString())


日志输出如下所示:

日志输出

我们可以看到无法启动协程的线程,有时它是DefaultDispatcher-worker-1或DefaultDispatcher-worker-2或DefaultDispatcher-worker-3。

调度员如何解决上述问题?

调度程序帮助协程确定必须执行工作的线程。调度程序作为参数传递给GlobalScope ,方法是根据我们希望协程执行的工作,提及可以使用哪种类型的调度程序。

调度员类型

主要有4种类型的调度程序。

  1. 主调度员
  2. IO分派器
  3. 默认调度程序
  4. 无限制调度程序

主调度员:

它在主线程中启动协程。它通常在需要在协程中执行UI操作时使用,因为只能从主线程(也称为UI线程)更改UI。

科特林

GlobalScope.launch(Dispatchers.Main) {
       Log.i("Inside Global Scope ",Thread.currentThread().name.toString())
           // getting the name of thread in which 
              // our coroutine has been launched
       }
       Log.i("Main Activity ",Thread.currentThread().name.toString())

主调度程序日志输出

IO分派器:

它在IO线程中启动协程,用于执行所有数据操作,例如联网,从数据库读取或写入,读取或写入文件,例如:从数据库中获取数据是IO操作,它在IO线程上完成。

科特林

GlobalScope.launch(Dispatchers.IO) {
       Log.i("Inside IO dispatcher ",Thread.currentThread().name.toString())
           // getting the name of thread in which
              // our coroutine has been launched
       }
       Log.i("Main Activity ",Thread.currentThread().name.toString())

IO调度程序日志输出

默认调度程序:

它在默认线程中启动协程。当我们计划进行复杂且长时间运行的计算时,应该选择此选项,这可能会阻塞主线程并冻结UI,例如:假设我们需要进行10,000次计算,并且正在UI线程上进行所有这些计算,即main线程,如果我们等待结果或10,000个计算,那么到那个时候,我们的主线程将被阻塞,我们的UI将被冻结,从而导致糟糕的用户体验。因此,在这种情况下,我们需要使用默认线程。 Dispatchers代表在GlobalScope中启动协程时使用的默认调度程序。默认值,并且使用共享的后台线程池,因此launch(Dispatchers.Default){…}与GlobalScope.launch {…}使用相同的调度程序。

科特林

GlobalScope.launch(Dispatchers.Default) {
        Log.i("Inside Default dispatcher ",Thread.currentThread().name.toString())
            // getting the name of thread in which 
              // our coroutine has been launched
        }
        Log.i("Main Activity ",Thread.currentThread().name.toString())

愚蠢的调度员

无限制调度程序:

顾名思义,无限制调度程序不限于任何特定线程。它在当前调用框架中执行协程的初始延续,并让协程在相应的挂起函数使用的任何线程中恢复,而无需强制执行任何特定的线程策略。

想要一个节奏更快,更具竞争性的环境来学习Android的基础知识吗?
单击此处,前往由我们的专家精心策划的指南,以使您立即做好行业准备!