【问题标题】:Does GlobalScope.launch create a new thread or run in the same thread?GlobalScope.launch 是创建一个新线程还是在同一个线程中运行?
【发布时间】:2019-08-16 06:07:28
【问题描述】:

我对此代码有疑问。

https://kotlinlang.org/docs/reference/coroutines/basics.html

fun main() {
    GlobalScope.launch { // launch new coroutine in background and continue
        delay(1000L) // non-blocking delay for 1 second (default time unit is ms)
        println("World!") // print after delay
    }
    println("Hello,") // main thread continues while coroutine is delayed
    Thread.sleep(2000L) // block main thread for 2 seconds to keep JVM alive
}

我将 delay(1000L) 替换为 Thread.sleep(1000L)。如果 GlobalScope.launch 块将在同一线程中运行,则 Thread.sleep(1000L) 将阻塞该线程。不过好像没有。

fun main() {
    GlobalScope.launch { // launch new coroutine in background and continue
        Thread.sleep(1000L)
        println("World!")
    }
    println("Hello,") // 
    Thread.sleep(2000L) // block main thread for 2 seconds to keep JVM alive
} 

【问题讨论】:

  • 找到了。在这 2 个示例中,GlobalScope.launch 在不同的线程中运行。

标签: kotlin kotlin-coroutines


【解决方案1】:

GlobalScope 允许您启动或多或少与daemon threads 具有相同行为的协程,因为它们与任何协程-Job 分离,并且基本上与应用程序一样长时间运行。它们的生命周期仅受应用程序本身的限制。这是您想通过使用“structured concurrency”来避免的事情,这基本上意味着您的协程应该以一种您可以控制它们的方式嵌套,而无需手动跟踪它们的引用并加入它们以等待它们的计算。因此,在您的实际代码中,您应该尽可能避免使用GlobalScope,因为肯定有更好的解决方案。

至于您的问题,正如已经提到的,GlobalScopeDispatchers.Default 池上运行,这意味着您将阻止一些工作线程,但不会阻止您从中生成协程的那个.

另一方面,如果你要写这个块:

fun main() {
    runBlocking { 
        Thread.sleep(1000L) 
        println("World!") 
    }
    println("Hello,") 
    Thread.sleep(2000L) 
}

您会看到协程阻塞了main 线程,并且输出将显示不同的结果。这是因为 runBlocking 在调用者线程 main 上运行,而不是在工作池线程之一上运行。

【讨论】:

    【解决方案2】:

    GlobalScope.launch { } 不一定创建一个新线程,但它会使用共享池中的一个,因为它使用Default 调度程序。因此,就您的问题而言,在您的 sn-p 中,传递给 launch 的块确实在不同的线程中运行。

    在有关dispatchers and threads 的文档中,您会发现以下内容:

    在 GlobalScope 中启动协程时使用的默认调度程序由 Dispatchers.Default 表示,并使用共享后台线程池

    而在Dispatchers.Default doc,你可以找到:

    默认情况下,此调度程序使用的最大并行度等于 CPU 内核数,但至少为两个。并行度 X 保证在此调度程序中最多可以并行执行 X 个任务。

    请注意,您可以通过提供一个作为 launch 的参数来更改调度程序。

    【讨论】:

    • “但它将使用共享池中的一个”。如果 CPU 至少有 2 个内核,您是否暗示 GlobalScope.launch { } 在另一个线程中运行?
    • 并非如此。事实上,池至少包含 2 个线程,即使对于单个代码处理器也是如此。如果我理解正确,那就是文档所说的。
    【解决方案3】:

    GlobalScope.launch{..} 函数不会阻塞。它返回一个Job 对象,您可以使用它来等待结果。

    在幕后,GlobalScope 使用默认调度程序 Dispatchers.Default。例如,您可以通过在launch{..} 函数中打印线程名称来看到它。

    由于Thread.sleep 调用,您需要运行更多协程才能看到它们相互阻塞。

    https://kotlinlang.org/docs/reference/coroutines/coroutine-context-and-dispatchers.html

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-04-01
      • 2021-05-08
      • 2014-01-27
      • 1970-01-01
      • 2018-07-03
      • 1970-01-01
      • 2016-06-09
      相关资源
      最近更新 更多