返回顶部
首页 > 资讯 > 前端开发 > node.js >为什么放弃使用Kotlin中的协程
  • 138
分享到

为什么放弃使用Kotlin中的协程

2024-04-02 19:04:59 138人浏览 八月长安
摘要

这篇文章主要讲解了“为什么放弃使用Kotlin中的协程”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“为什么放弃使用Kotlin中的协程”吧!调试请看下面一段

这篇文章主要讲解了“为什么放弃使用Kotlin中的协程”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“为什么放弃使用Kotlin中的协程”吧!

调试

请看下面一段代码。

suspend fun retrieveData(): SomeData {     val request = createRequest()     val response = remoteCall(request)     return postProcess(response) }  private suspend fun remoteCall(request: Request): Response {    // do suspending REST call }

假设我们要调试 retrieveData 函数,可以在第一行中放置一个断点。然后启动调试器(我使用的是  IntelliJ),它在断点处停止。现在我们执行一个 Step Over(跳过调用 createRequest),这也正常。但是如果再次 Step  Over,程序就会直接运行,调用 remoteCall() 之后不会停止。

为什么会这样?JVM 调试器被绑定到一个 Thread  对象上。当然,这是一个非常合理的选择。然而,当引入协程之后,一个线程不再做一件事。仔细一看:remoteCall(request) 调用的是一个 suspend  函数,虽然我们在调用它的时候并没有在语法中看到它。那么会发生什么?我们执行调试器 "step over ",调试器运行 remoteCall  的代码并等待。

这就是难点所在:当前线程(我们的调试器被绑定到该线程)只是我们的coroutine 的执行者。当我们调用 suspend  函数时,会发生的情况是,在某个时刻,suspend 函数会 yield。这意味着另外一个 Thread 将继续执行我们的方法。我们有效地欺骗了调试器。

我发现的唯一的解决方法是在我想执行的行上放置一个断点,而不是使用Step Over。不用说,这是个大麻烦。而且很显然,这不仅仅是我一个人的问题。

此外,在一般的调试中,很难确定一个单一的 coroutine 当前在做什么,因为它在线程之间跳跃。当然,coroutine  是有名字的,你可以在日志中不仅打印线程,还可以打印 coroutine 的名字,但根据我的经验,调试基于 coroutine  的代码所需的心智负担,要比基于线程的代码高很多。

REST 调用中绑定 context 数据

微服务开发,一个常见的设计模式是,接收一个某种形式认证的 REST  调用,并将相同的认证传递给其他微服务的所有内部调用。在最简单的情况下,我们至少要保留调用者的用户名。

然而,如果这些对其他微服务的调用在我们调用栈中嵌套了 10 层深度怎么办?我们当然不希望在每个函数中都传递一个认证对象作为参数。我们需要某种形式的  "context",这种 context 是隐性存在的。

在传统的基于线程的框架中,如 spring,解决这个问题的方法是使用 ThreadLocal  对象。这使得我们可以将任何一种数据绑定到当前线程。只要一个线程对应一个 REST 调用(你应该始终以这个为目标),这正是我们需要的。这个模式的很好的例子是  Spring 的 SecurityContextHolder。

对于 coroutine,情况就不同了。一个 ThreadLocal  不再对应一个协程,因为你的工作负载会从一个线程跳到另一个线程;不再是一个线程在其整个生命周期内伴随一个请求。在 Kotlin coroutine 中,有  CoroutineContext。本质上,它不过是一个 HashMap,与 coroutine 一起携带(无论它运行在哪个线程上)。它有一个可怕的过度设计的  api,使用起来很麻烦,但这不是这里的主要问题。

真正的问题是,coroutine 不会自动继承上下文。

例如:

suspend fun sum(): Int {     val jobs = mutableListOf<Deferred<Int>>()     for(child in children){         jobs += async {  // we lose our context here!             child.evaluate()          }     }     return jobs.awaitAll().sum() }

每当你调用一个 coroutine builder,如 async、runBlocking 或 launch,你将(默认情况下)失去你当前的  coroutine 上下文。你可以通过将上下文显式地传递到 builder 方法中来避免这种情况,但是上帝保佑你不要忘记这样做(编译器不会管这些!)。

一个子 coroutine 可以从一个空的上下文开始,如果有一个上下文元素的请求进来,但没有找到任何东西,可以向父 coroutine  上下文请求该元素。然而,在 Kotlin 中不会发生这种情况,开发人员需要手动完成,每一次都是如此。

如果你对这个问题的细节感兴趣,我建议你看看这篇博文。

https://blog.tpersson.io/2018/04/22/emulating-request-scoped-objects-with-kotlin-coroutines/

synchronized 不再如你想的那样工作

在 Java 中处理或 synchronized 同步块时,我考虑的语义通常是  "当我在这个块中执行时,其他调用不能进入"。当然“其他调用”意味着存在某种身份,在这里就是线程,这应该在你的脑海中升起一个大红色的警告信号。

看看下面的例子。

val lock = ReentrantLock()  suspend fun doWithLock(){    lock.withLock {        callSuspendingFunction()    } }

这个调用很危险,即使 callSuspendingFunction() 没有做任何危险的操作,代码也不会像你想象的那样工作。

  • 进入同步锁

  • 调用 suspend 功能

  • 协程 yield,当前线程仍然持有锁。

  • 另一个线程继续我们的 coroutine

  • 还是同一个协程,但我们不再是锁的 owner 了!

潜在的冲突、死锁或其他不安全的情况数量惊人。你可能会说,我们只是需要设计我们的代码来处理这个问题。我同意,然而我们谈论的是 JVM。那里有一个庞大的  Java 库生态。而它们并没有做好处理这些情况的准备。

这里的结果是:当你开始使用 coroutine 的时候,你就放弃了使用很多 Java 库的可能性,因为它们目前只能工作在基于线程的环境。

单机吞吐量与水平扩展

对于服务器端来说,coroutine 的一大优势是,一个线程可以处理更多的请求;当一个请求等待数据库响应时,同一个线程可以愉快地服务另一个请求。特别是对于  I/O 密集型任务,这可以提高吞吐量。

然而,正如这篇博文所希望向您展示的那样,在许多层面上,使用 coroutine 都有一个非零成本的开销。

由此产生的问题是:这个收益是否值得这个成本?而在我看来,答案是否定的。在云和微服务环境中,有一些现成的扩展机制,无论是 Google  AppEngine、AWS Beanstalk 还是某种形式的  kubernetes。如果当前负载增加,这些技术将简单地按需生成你的微服务的新实例。因此,考虑到引入 coroutine  带来的额外成本,单一实例所能处理的吞吐量就不那么重要了。这就降低了我们使用 coroutine 所获得的价值。

Coroutine 有其存在的价值

话说回来,Coroutine 还是有其使用场景。当开发只有一个 UI 线程的客户端 UI 时,coroutine 可以帮助改善你的代码结构,同时符合 UI  框架的要求。听说这个在安卓系统上很好用。Coroutine 是一个有趣的主题,然而对于服务器端开发来说,我觉得协程还差点意思。JVM 开发团队目前正在开发  Fiber,本质上也是 coroutine,但他们的目标是与 JVM 基础库更好共存。这将是有趣的,看它将来如何发展,以及 Jetbrains 对 Kotlin  coroutine 对此会有什么反应。在最好的情况下,Kotlin coroutine 将来只是简单映射到 Fiber  上,而调试器也能足够聪明来正确处理它们。

感谢各位的阅读,以上就是“为什么放弃使用Kotlin中的协程”的内容了,经过本文的学习后,相信大家对为什么放弃使用Kotlin中的协程这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!

--结束END--

本文标题: 为什么放弃使用Kotlin中的协程

本文链接: https://lsjlt.com/news/84936.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 为什么放弃使用Kotlin中的协程
    这篇文章主要讲解了“为什么放弃使用Kotlin中的协程”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“为什么放弃使用Kotlin中的协程”吧!调试请看下面一段...
    99+
    2024-04-02
  • 为什么放弃使用Lombok
    这篇文章主要介绍“为什么放弃使用Lombok”,在日常操作中,相信很多人在为什么放弃使用Lombok问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”为什么放弃使用Lombok”的疑惑有所帮助!接下来,请跟着小编...
    99+
    2023-06-16
  • 为什么放弃用Spring Boot中的RestTemplate
    这篇文章主要讲解了“为什么放弃用Spring Boot中的RestTemplate”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“为什么放弃用Spring Boot中的RestTemplate...
    99+
    2023-06-16
  • 为什么有人选择放弃使用Golang?
    为什么有人选择放弃使用Golang? 近年来,随着计算机科学领域的不断发展,越来越多的编程语言被开发出来,其中Golang作为一门具有高效性能和并发特性的编程语言,在一定范围内受到了广...
    99+
    2024-03-01
    生态系统 性能问题 学习曲线
  • Kotlin协程的工作原理是什么
    这篇文章主要讲解了“Kotlin协程的工作原理是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Kotlin协程的工作原理是什么”吧!协程的状态机这一章会...
    99+
    2024-04-02
  • Kotlin关于协程是什么的探究
    目录Kotlin协程是什么suspend是什么总结Kotlin协程是什么 本文只是自己经过研究后,对 Kotlin 协程的理解概括,如有偏差,还请斧正。 简要概括: 协程是 Kotl...
    99+
    2023-01-12
    Kotlin协程原理 Kotlin协程的使用 Kotlin协程并发
  • kotlin之协程的理解与使用详解
    前言         为什么在kotlin要使用协程呢,这好比去了重庆不吃火锅一样的道理。协程的概念并不陌生,在python也有提及。任何事务...
    99+
    2024-04-02
  • kotlin协程异常处理的方法是什么
    Kotlin协程的异常处理方法有以下几种:1. 使用try/catch块:在协程内部使用try/catch块来捕获异常,并对异常进行...
    99+
    2023-09-20
    kotlin
  • Kotlin协程的基础与使用示例详解
    目录一.协程概述1.概念2.特点3.原理1)续体传递2)状态机二.协程基础1.协程的上下文2.协程的作用域3.协程调度器4.协程的启动模式5.协程的生命周期1)协程状态的转换2)状态...
    99+
    2024-04-02
  • 放弃Golang编程语言的背后真正原因是什么?
    放弃Golang编程语言的背后真正原因是什么? 作为一种高效、静态类型的编程语言,Golang(又称Go)自诞生以来备受程序员的青睐。然而,随着时间的推移,一些开发者开始放弃Golan...
    99+
    2024-03-01
    性能 兼容性 失望 标准库
  • Kotlin 协程异步热数据流的设计与使用讲解
    目录一.异步冷数据流二.异步热数据流1.异步热数据流的设计1)SharedFlow接口2)MutableSharedFlow接口2.异步热数据流的使用1)MutableSharedF...
    99+
    2024-04-02
  • python中协程的作用是什么
    python中协程的作用是什么?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。Python的优点有哪些1、简单易用,与C/C++、Java、C# 等传统语言相比,...
    99+
    2023-06-14
  • Python使用协程的缺点是什么
    这篇文章给大家分享的是有关Python使用协程的缺点是什么的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。多核资源不能使用:协程的本质是单线程,它不能同时使用单个CPU的多核、协程。在多CPU上运行程需要与过程配合...
    99+
    2023-06-25
  • 为什么wait和notify必须放在synchronized中使用
    目录wait/notify基础使用wait/notify和synchronized一起用?原因分析wait和notify问题复现总结前言: 在多线程编程中,wait 方法是让当前线程...
    99+
    2024-04-02
  • android中Kotlin的用法是什么
    Kotlin是一种现代化的编程语言,它是在Java虚拟机(JVM)上运行的,并且与Java语言可以很好地互操作。它被广泛用于Andr...
    99+
    2023-10-25
    android Kotlin
  • kotlin中hashmap的用法是什么
    在Kotlin中,HashMap是一种可变的集合,用于存储键值对。以下是HashMap的基本用法示例: // 创建一个空的HashM...
    99+
    2024-04-02
  • 怎么在python3协程中使用asyncio
    怎么在python3协程中使用asyncio?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。Python主要用来做什么Python主要应用于:1、Web开发;2、...
    99+
    2023-06-14
  • 为什么不要用Java的语法思维来写Kotlin
    这篇文章主要讲解了“为什么不要用Java的语法思维来写Kotlin”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“为什么不要用Java的语法思维来写Kotlin”吧!1.尽可能的少用 !!个人...
    99+
    2023-06-17
  • 很多用户放弃iPhone的7个原因,你中枪了吗?看完是否想用华为
    很多用户放弃iPhone的7个原因,你中枪了吗?看完是否想用华为 iPhone手机在国内部分手机用户心中还是很难进行选择的,那么对于9月份的即将到来,很多人都在考虑是否入手iPhone的2019年版,...
    99+
    2024-04-02
  • Go中什么是协程,协程和线程的区别和联系
    在Go中,协程(Goroutine)是一种轻量级的线程,由Go运行时环境管理。协程是一种用户态的线程,不需要操作系统的线程支持。在G...
    99+
    2023-09-23
    Go
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作