我正在使用一个测试文件try Kotlin协程.我观察到的是,块,完成,然后下一个dec块开始.

 @Test
  fun `xyz`() {

    runBlocking {
      val x = async {
        x()
      }
      val y = async {
        y()
      }
      val z = async {
        z()
      }
      println("x, y, z -> ${x.await()} , ${y.await()}, ${z.await()} ")
    }


  }

  fun x() = "x".also {
    repeat(1000) {
      println("waiting for network response.")
    }
    println("returning x")
  }

  fun y() = "y".also { println("returning y") }
  fun z() = "z".also { println("returning z") }

在这个代码块中,我可以看到"返回y"和"返回z"只有在x()调用完成后才会打印出来.这不是我期望Kotlin运行的方式.你能告诉我我需要做什么改变才能同时运行三个调用,或者不等待一个调用完成. PS -测试方法中的代码也可以直接在main上运行.:)

推荐答案

这是一个有趣的问题,您没有获得预期的异步行为的原因来自您的runBlocking函数及其创建的上下文BlockingEventLoop.当使用此调度程序运行协程时,您将仅在单个Thread中工作.尽管从技术上讲,async会异步启动协程,但对于您的例子来说,只有在执行像delay这样的非阻塞操作时才会看到这种行为,这只是因为delay调度,但这当然不是您要找的.您可能对让async工作感兴趣的范围上下文是IODefaultUnconfined,但我认为Default在您的例子中应用得最好.请记住,单元测试通常需要像runBlockingrunTest那样启动阻塞上下文,因此只有当您已经在协程作用域中(即在suspend函数中或使用以runBlocking开头的作用域)并且上下文已经是非阻塞时,使用coroutineScope可能才有效.这里有3个不同版本的你自己的代码和3个不同的例子:一个是阻塞的,另一个是2种不同风格的非阻塞的.

@Test
fun `should xyz synchronously in spite of async`() {
    runBlocking {
        val x = async {
            "x".also {
                repeat(1000) {
                    println("waiting for network response.")
                }
                println("returning x")
            }
        }
        val y = async {
            "y".also { println("returning y") }
        }
        val z = async {
            "z".also { println("returning z") }
        }
        println("x, y, z -> ${x.await()} , ${y.await()}, ${z.await()} ")
        println(coroutineContext)
    }
}

@Test
fun `should xyz asynchronously because of non-blocking with explicit Dispatchers_IO`() {
    runBlocking {
            withContext(Dispatchers.Default) {
                val x = async {
                    "x".also {
                        repeat(1000) {
                            println("waiting for network response.")
                        }
                        println("returning x")
                    }
                }
                val y = async {
                    "y".also { println("returning y") }
                }
                val z = async {
                    "z".also { println("returning z") }
                }
                println("x, y, z -> ${x.await()} , ${y.await()}, ${z.await()} ")
                println(coroutineContext)
            }
    }
}
@Test
fun `should xyz asynchronously because of non-blocking  with coroutineScope`():Unit = runBlocking {
            coroutineScope {
                CoroutineScope(Dispatchers.Default).launch {
                    val x = async {
                        "x".also {
                            repeat(1000) {
                                println("waiting for network response.")
                            }
                            println("returning x")
                        }
                    }
                    val y = async {
                        "y".also { println("returning y") }
                    }
                    val z = async {
                        "z".also { println("returning z") }
                    }
                    println("x, y, z -> ${x.await()} , ${y.await()}, ${z.await()} ")
                    println(coroutineContext)
                }.join()
            }

}

请注意,正如@Joffrey所建议的那样,尽管这些示例用于明确Kotlin协程中的contextsscopes,但以下示例将是最正确的一个实现,以尊重称为structured concurrency的协程中非常重要的概念.这是一个更复杂的概念来理解,但一般来说,我们应该避免上下文切换时,它是不必要的:

@Test
fun `should xyz asynchronously because of non-blocking with explicit Dispatchers_IO`()  = runBlocking(Dispatchers.Default){
            val x = async {
                "x".also {
                    repeat(1000) {
                        println("waiting for network response.")
                    }
                    println("returning x")
                }
            }
            val y = async {
                "y".also { println("returning y") }
            }
            val z = async {
                "z".also { println("returning z") }
            }
            println("x, y, z -> ${x.await()} , ${y.await()}, ${z.await()} ")
            println(coroutineContext)
        }

还要确保在这些测试中考虑使用断言.它们是不完整的.他们只专注于回答你的问题.

Kotlin相关问答推荐

访问者闭包中的Kotlin序列yield 率

如何在操作系统版本上正确获取Room数据库的路径>;=26 sdk?

如何在 micronaut 上启用 swagger UI?

具有泛型类型的 Kotlin 密封接口不会为其子类型推断约束

如何在 Kotlin 中将with代码转换为完整代码?

Kotlin 条件格式字符串

如何通过 compose 处理剪切区域?

奇怪的 cotlin check Not Null 参数错误

parallelStream()和asSequence().asStream().parallel()之间的区别

为什么 Kotlin 扩展运算符在传递原始可变参数时需要 toTypedArray()?

下拉通知面板时是否可以暂停Android中的任何视频(媒体播放器)应用程序?

将 jetpack compose 添加到现有元素

如何在顶级函数中使用 koin 注入依赖项

如何在Spring Boot应用程序上启用承载身份验证?

如果 Maybe 完成,则从其他来源将 Maybe 转换为 Single

Jacoco在Gradle 7.0.2和Kotlin 1.5.10上失败

用mockk验证属性设置程序吗?

Android Studio - java.io.IOException:无法生成 v1 签名

比较Kotlin的NaN

RxJava - 每秒发出一个 observable