Kotlin 1.4.0-RC协程调试

我们仍将重点放在1.4版本中发生的变化。在这篇博客中,我们要介绍协程相关的几个重要特性:

  • 协程调试更加方便
  • 深度递归函数已可定义

在1.4.0-RC版本中已能体验这些变动!

img

现在让我们深入了解!

协程的调试

协程非常适合异步编程(但不仅限于此),而且已经有很多人已经或开始使用协程了。但是当使用协程编写代码时,调试将是非常痛苦的事。协程在线程之间切换。可能难以理解指定协程的功能或监控其上下文。在某些情况下,无法跟踪断点上的step。这导致必须依靠日志记录或消耗精力来使用协程调试代码。为了解决这个问题,我们在Kotlin插件中引入了新功能,以便于协程的调试。

*Debug Tool Window 现在包含一个新的 Coroutines *选项卡。默认情况下它是显示的,你可以显示和隐藏它:

在该选项卡,你可以看到当前在运行和已暂停协程的相关信息。协程由执行它们的调度器进行分组。如果启动协程时给予自定义名称,则可以在工具窗口中找到这个名称。在下面的示例中,可以看到主协程正在运行(已在断点处停止),而其他四个协程已挂起:

新功能让你可以检查每个协程的状态并查看局部变量和被捕获变量的值。这同样适用于已挂起的协程!

在该示例中,我们检查了已挂起协程局部变量的值:

选择一个被挂起的协程(点击invokeSuspend以查看其状态),Variables选项卡将显示局部变量的状态:

img

现在你可以看到完整的协程创建堆栈以及协程内部的调用堆栈:

通过Get Coroutines Dump可获取包含每个协程及其堆栈状态的完整报告:

目前,协程转储文件比较简单,但我们将在后续版本增强其可读性,提升其作用。

请注意,要使调试器在协程内部的指定断点处停止,需要对该断点勾选Suspend: All选项:

若要尝试这个调试协程的新功能,你需要使用最新版本的kotlinx.coroutines1.3.8-1.4.0-rc,以及最新版本的Kotlin插件)(例如1.4.0-rc-release-IJ2020.1 -2)。

该功能只适用于Kotlin/JVM。如果你遇到任何问题(请不要忘记与我们分享详细信息!),可以打开Build, Execution, Deployment | Debugger | Data Views | Kotlin中的Preferences,选择Disable coroutines agent以关闭它。目前,我们正在发布该功能,以便能在实验状态下调试协程,我们期待你的反馈!

使用协程定义深度递归函数

在Kotlin 1.4中,你可以定义并执行深度大于100,000的递归函数,这由基于协程的标准库提供支持。

首先让我们看一个普通的递归函数,当递归深度过高时,其用法会导致StackOverflowError。之后,我们将讨论如何处理该问题并使用Kotlin标准库重写功能。

我们将使用一个简单的二叉树,其中每个Tree节点都有对其leftright子节点的引用:

树的深度,是树的根到其最长路径子节点的长度。可以使用以下递归函数进行计算:

树的深度是左右子节点的深度最大值加一。树无子节点时为零。

当递归深度较小时,该函数能正常执行:

但如果创建的树深度大于100,000,这在实际场景中并不少见,那么你将得到StackOverflowError

根源是调用栈变得过大了。要解决该问题,可以通过VM配置来增加最大栈大小。但是这只适用于特定的场景,通常情况下并不是一个可行的解决方案。

另外,你还可以重写代码,手动将过程中的结果存在堆中而不是栈中。这个解决方案在大多数情况下都有用,并且在其他语言中很常见。但是最后代码会变得复杂且难以理解,忘记了简洁优雅的初衷。你可以在这里找到示例。

基于协程的机制,现在Kotlin提供了一种解决该问题的精巧方案。

Kotlin库现在包含DeepRecursiveFunction定义,这个定义通过挂起机制对递归调用进行建模:

你可以比较两个版本,最初的版本和使用了DeepRecursiveFunction的版本,以确保逻辑不变。现在你的新函数变成了类型为DeepRecursiveFunction的变量,你可以通过‘invoke’协议作为depthFunction(t)进行调用。现在,函数体成为DeepRecursiveFunction的lambda参数主体,并且递归调用已替换为callRecursive。这些改动非常简单直接。请注意,虽然新的depth函数在背后使用了协程,但它本身并不是suspend函数。

了解DeepRecursiveFunction的实现方式很有意思,但是不了解亦不阻碍你的使用,并从中获得收益。可以在这篇博客中了解实现的详细信息。

DeepRecursiveFunction是Kotlin标准库的一部分,而不是kotlinx.coroutines库的一部分,因为它与异步编程无关。目前该API仍处于实验阶段,我们期待你的反馈!

如何尝试

同样,你可以在 play.kotl.in在线使用Kotlin

IntelliJ IDEA,你可以更新Kotlin插件到1.4.0-RC版本。操作指南

如果要在预览版安装之前创建的项目中使用,则需要在Gradle或Maven中针对预览版配置构建脚本。请注意,与以前的预览版不同,Kotlin 1.4.0-RC可直接通过Maven Central获取。这意味着你无需手动将kotlin-eap存储库添加到构建文件中。

你可以在Github发行页下载命令行编译器

分享你的反馈

如果你发现错误并向我们的问题跟踪器进行报告,我们表示非常感谢。我们尝试在最终发行版前解决所有重要问题,这意味着无需等到下一个Kotlin发行版你的问题便能得到解决。

如果你有任何疑问并想参与讨论,欢迎加入Kotlin Slack(在这里获得邀请)的#eap channel频道。在该频道中,你还可以获取有关新预览版的通知。

Let’s Kotlin!

此条目发表在官方分类目录。将固定链接加入收藏夹。

发表评论

电子邮件地址不会被公开。 必填项已用*标注