我经常创建具有包含协程的函数的类。并不总是清楚该函数是否由绑定到UI的某个组件使用,或者它是否正在进行更多面向IO的后台工作。下面是一个例子:
fun myFunction() {
GlobalScope.launch {
// Do something
}
}在本例中,未指定Dispatcher.MAIN或Dispatchers.IO。这是正确的方法吗?协程是否使用调用客户端恰好正在使用的作用域?当我明确知道我需要一个特定的作用域时,我应该只指定一个调度程序吗?
发布于 2020-01-14 19:14:41
GlobalScope 将协程的生命周期绑定到应用程序本身的生命周期。这意味着从这个作用域开始的协程将继续存在,直到发生以下两种情况之一
强烈建议在GlobalScope实例上使用异步或启动。
未指定Dispatcher.MAIN或Dispatchers.IO。这是正确的方法吗?
是啊,有何不可呢?如果协程中的工作与UI或IO都不相关,那就去做吧。
当我明确知道我需要一个特定的作用域时,我应该只指定一个调度程序吗?
为了回答这个问题,让我们首先看看文档中对launch的定义,
fun CoroutineScope.launch(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit ): Job (source)我们正在讨论的Dispatcher是一种CoroutineContext。正如你在定义中看到的,如果没有提到CoroutineContext (这意味着我们也没有提到Dispatcher ),它默认设置为在内部使用Dispatchers.Default的EmptyCoroutineContext,这就是文档所说的,
所有标准构建器(如启动、异步等)使用的默认CoroutineDispatcher,如果在其上下文中既没有指定调度程序,也没有指定任何其他ContinuationInterceptor。
它是由JVM上的共享线程池支持的。默认情况下,此调度程序使用的最大线程数等于CPU核心数,但至少为两个。
因此,即使您忘记提到Dispatcher,Scheduler也会从池中随机挑选任何可用的线程,并将协程传递给它。但请确保在未提及调度程序的情况下不要启动任何与UI相关的工作。
发布于 2020-01-16 21:04:31
首先,您必须将作用域与上下文和调度程序区分开来。
协程范围主要是关于协程的生命周期,并处理结构化并发的概念。它可能有一个默认的调度程序,该调度程序在逻辑上与您将协程的生命周期绑定到的对象相关联。例如,如果您将协程范围限定为Android活动,则默认的调度程序将是UI。
协程上下文指的是调度程序。上下文应该在协程的执行过程中改变,因为里面的逻辑需要它。通常,您将使用withContext临时切换调度程序,以避免阻塞UI线程。您通常不会在线程池中启动整个协程,除非所有协程都在后台线程上运行(例如,没有UI交互)。
其次,dispatcher的选择应该与需要特定dispatcher的代码搭配。它应该发生在处理给定关注点的函数中,比如发出REST请求或DB操作。这再次强化了在启动协程时不决定调度器的做法。
发布于 2020-01-13 20:22:35
GlobalScope是一个EmptyCoroutineScope,所有用这个作用域启动的协程都像是演示线程。它们不能被取消,并且在完成之前保持活动状态。我建议实现一个特定的作用域,而不是使用GlobalScope,以便控制所有启动的协程。GlobalScope使用Dispatchers.Default作为默认调度程序,在您的示例中,您始终在默认调度程序中创建协程。
https://stackoverflow.com/questions/59715510
复制相似问题