为什么Kotlin忽略了延迟(timeMillis:Long)函数 上下文

为什么Kotlin忽略了延迟(timeMillis:Long)函数 上下文,kotlin,concurrency,kotlin-coroutines,Kotlin,Concurrency,Kotlin Coroutines,遵循Kotlin协作路线基础指南 使用此代码 fun coroutinesAreLightWeight() { runBlocking { repeat(100_000) { launch { delay(1000L) print("$it, ") } } } } 问题 当我在我的电脑上运行程序时,它会一次性打印出所有数字,而不是等待1

遵循Kotlin协作路线基础指南

使用此代码

fun coroutinesAreLightWeight()
{
    runBlocking {
        repeat(100_000) {
            launch {
                delay(1000L)
                print("$it, ")
            }
        }
    }
}
问题 当我在我的电脑上运行程序时,它会一次性打印出所有数字,而不是等待1秒后再打印下一个数字。当运行kotlin指南中所示的精确代码时,这种行为是相同的。似乎正在忽略
delay()
函数

起初,这段代码运行良好,但后来它停止了预期的工作。我正在将IntelliJ 2019.2.1与kotlin版本1.3.50一起使用,我尝试重新启动该程序,但这并没有解决我的问题

下面是整个班级的样子

class CoroutinesBasics
{
    fun ...

    fun ...

    fun coroutinesAreLightWeight()
    {
        runBlocking {
            repeat(100_000) {
                launch {
                    delay(1000L)
                    print("$it, ")
                }
            }
        }
    }
}
coroutinesAreLightWeight()
函数的调用方式如下

fun main()
{
    CoroutineBasics().apply{
        ....
        ....
        coroutinesAreLightWeight()
    }
}
有人能告诉我发生了什么事吗?这是科特林虫吗

Kotlin依赖项
implementation'org.jetbrains.kotlinx:kotlinx coroutines core:1.3.0'

据我所知,这是预期的行为,因为coroutines同时工作,所以您的代码将只等待1秒,等待当前正在工作的所有coroutines

我推荐的一个关于协作的好话题是:

幻灯片中的示例与此完全相同:)


如果您想让他们等待,您应该将repeat移到“runBlocking”之外。

据我所知,这是预期的行为,因为协同路由同时工作,所以对于当前正在工作的所有协同路由,您的代码将只等待1秒

我推荐的一个关于协作的好话题是:

幻灯片中的示例与此完全相同:)


如果您想让他们等待,您应该将重复移动到“运行阻塞”之外。

我将从另一个角度回答这个问题。
该示例是在特定上下文中给出的。也就是说,“协同程序不像线程”。本示例的目标不是演示如何延迟打印数字,而是演示与线程不同的协同路由可以同时启动数千次。这正是这段代码所做的。它提交它们,然后执行它们

你可能会问,为什么它们都是顺序的?它们不应该同时运行吗?
为此,让我们打印线程名称:

repeat(100_000) {
    launch {
       delay(100L)
       println("$it, ${Thread.currentThread().name}")
    }
}
您将很快看到原因:
99999,main

由于您使用的是
运行阻塞
,因此所有协同程序都由一个线程执行

但我们可以改变它:

runBlocking {
    repeat(100_000) {
        launch(Dispatchers.Default) {
            delay(100L)
            println("$it, ${Thread.currentThread().name}")
        }
    }
}
通过使用
Dispatchers.Default
,我们在一个默认线程池上运行我们的协同程序。结果变得不那么可预测:

98483, DefaultDispatcher-worker-6
99898, DefaultDispatcher-worker-5
99855, DefaultDispatcher-worker-1
99706, DefaultDispatcher-worker-2
默认的线程池从2个线程开始,默认情况下增加到CPU核心数。您可以查看
createDefaultDispatcher()
了解实际实现

关于
Thread.sleep()
,您应该知道一些事情:

  • 切勿在协同程序中使用
    Thread.sleep()
  • 切勿在协同程序中使用
    Thread.sleep()
  • IntelliJ甚至会警告您不要在协同程序中使用
    Thread.sleep()
  • 让我们看看下面的例子来了解原因:

    repeat(100_000) {
       launch {
          Thread.sleep(100) 
          println("$it, ${Thread.currentThread().name}")
       }
    }
    
    你可以假设你说的是“在100毫秒内不要在这个区块内做任何事情”

    但实际上你说的是“100毫秒内不要做任何事情”


    由于
    launch
    将在它从
    runBlocking
    获得的上下文上执行,并且
    runBlocking
    是一个单线程上下文,因此您将阻止所有协程的执行。

    我将从另一个角度来回答这个问题。
    该示例是在特定上下文中给出的。也就是说,“协同程序不像线程”。本示例的目标不是演示如何延迟打印数字,而是演示与线程不同的协同路由可以同时启动数千次。这正是这段代码所做的。它提交它们,然后执行它们

    你可能会问,为什么它们都是顺序的?它们不应该同时运行吗?
    为此,让我们打印线程名称:

    repeat(100_000) {
        launch {
           delay(100L)
           println("$it, ${Thread.currentThread().name}")
        }
    }
    
    您将很快看到原因:
    99999,main

    由于您使用的是
    运行阻塞
    ,因此所有协同程序都由一个线程执行

    但我们可以改变它:

    runBlocking {
        repeat(100_000) {
            launch(Dispatchers.Default) {
                delay(100L)
                println("$it, ${Thread.currentThread().name}")
            }
        }
    }
    
    通过使用
    Dispatchers.Default
    ,我们在一个默认线程池上运行我们的协同程序。结果变得不那么可预测:

    98483, DefaultDispatcher-worker-6
    99898, DefaultDispatcher-worker-5
    99855, DefaultDispatcher-worker-1
    99706, DefaultDispatcher-worker-2
    
    默认的线程池从2个线程开始,默认情况下增加到CPU核心数。您可以查看
    createDefaultDispatcher()
    了解实际实现

    关于
    Thread.sleep()
    ,您应该知道一些事情:

  • 切勿在协同程序中使用
    Thread.sleep()
  • 切勿在协同程序中使用
    Thread.sleep()
  • IntelliJ甚至会警告您不要在协同程序中使用
    Thread.sleep()
  • 让我们看看下面的例子来了解原因:

    repeat(100_000) {
       launch {
          Thread.sleep(100) 
          println("$it, ${Thread.currentThread().name}")
       }
    }
    
    你可以假设你说的是“在100毫秒内不要在这个区块内做任何事情”

    但实际上你说的是“100毫秒内不要做任何事情”


    由于
    launch
    将在它从
    runBlocking
    获得的上下文上执行,并且
    runBlocking
    是一个单线程上下文,因此您可以阻止所有协同程序的执行。

    但是根据Kotlin协同程序指南,它的内容是“它启动100K个协同程序,一秒钟后,每个协同程序打印一个点。”你能在
    runBlocking{repeat(100_000)之前打印一些东西吗{
    或者将延迟时间增加10秒,这样你就可以知道它是否正在等待。你的代码将发生什么:它将为你创建100000个协程,每个协程将等待1秒,然后打印。因此,在一秒钟后,你将有100000个打印。因为该块中的所有代码将同时工作,因为
    delay
    线程.sleep<