Project Loom:Reactive模型和协程进行时(翻译)
Java 15将发布Project Loom的第一个版本。我相信这将改变JVM。在这篇文章中,我想深入探讨一下导致我相信这一点的原因。
首先,我们需要了解核心问题。然后,我将尝试描述以前的技术如何解决它。之后,我们将看到Project Loom采取的方法。最后,我将推断后者可能对生态系统产生什么影响。
Project Loom
我们首先必须记住,很长一段时间以来,计算机只有一个内核。即使这样,还是需要同时运行多个程序:这至少要运行两个操作系统和适当的程序。
为了实现并行性的幻觉,它依赖于一个技巧。它运行一个程序,如果该程序没有在特定的时间范围内完成,它将存储其状态以供以后使用。然后,它运行下一个要运行的程序。有几种算法可用来调度下一个程序:循环调度,加权循环调度等。好处是,所有这些都可以通过操作系统线程的概念很好地从开发人员中抽象出来。该操作系统通吃繁重的护理,包括存储执行的状态。但是,线程有两个缺点:
- 线程很重,因为它带有很多状态
- 线程需要大量的机器资源来创建
在所有情况下,现代OS都允许M个线程,其中M是数千个线程。现代机器是多核的,提供N个核,比M少两个数量级。拥有多个内核(无论是物理内核还是虚拟内核)并不会从根本上改变底层机制:M远高于N,并且OS负责从线程到内核的映射。
阻塞线程
面的模型在传统方案中效果很好,但在网络方案中效果不佳。假设有一个Web服务器需要响应HTTP请求。在过去不太好的时候,CGI是处理请求的一种方法。它将每个请求映射到一个流程,以便处理创建整个新流程所需的请求,并在发送响应后将其清除。
Java EE应用程序服务器极大地改善了这种情况,因为实现将线程保留在池中以供以后重用。但是,想象一下响应的生成需要时间,例如因为它需要访问数据库以读取数据。在数据库返回数据之前,线程需要等待。
这意味着线程实际上正在等待其生命周期的大部分时间。一方面,此类线程自己不使用任何CPU。另一方面,它使用其他种类的资源,尤其是内存。
同样,太多线程是操作系统的负担:操作系统必须在数量有限的CPU内核上平衡大量线程。这花费了宝贵的CPU周期,因此,操作系统正在与应用程序竞争CPU。
现在,并发请求的数量可以远远超过服务器可用的线程数量。因此,阻塞的线程浪费资源,并使服务器无响应。为了解决这个问题,可以添加更多的Web服务器来处理负载:这是水平缩放。
在大多数情况下,水平缩放就足够了。等待阻塞线程所花费的时间是浪费的,但是没有任何相关的费用...除非一个人的基础架构位于'云'中。在那种情况下,人们要为未使用的资源付费:这绝不是一个明智的主意。
单线程,反应式和Kotlin协程模型
对于开发人员来说,管理多个线程很复杂。例如,如果您一直在使用(或开发)Swing应用程序,则可能知道“灰色矩形效果”。当用户与窗口的交互(例如单击)启动长时间运行的任务时,就会发生这种情况。如果将另一个窗口移到Swing窗口上,然后再移出,Swing不会重画另一个窗口与Swing窗口相交的区域,而不会留下难看的灰色矩形。原因是长时间运行的任务是在“ 事件调度线程”上启动的,而不是在专用线程上启动的。而且这很容易避免,甚至不涉及在共享的可变状态上进行同步!
为了避免这种情况,某些堆栈完全禁止开发人员使用多个线程。例如,Node.js的API仅提供一个非阻塞事件循环线程:提交的函数采用回调的形式。请注意,这不会阻止实现使用多个线程。
该反应的方法是另一种选择,其实颇为相似。尽管它摆脱了单线程API的限制,并提供了反压力机制,但它仍然需要非阻塞代码。由于OS线程很昂贵,因此Reactive将它们池化,并在整个应用程序生命周期中重复使用它们。核心过程是从池中获取空闲线程,让其执行代码,然后将线程释放回池中。这就是为什么它需要非阻塞代码的原因:如果代码阻塞了,那么执行线程将不会被释放,并且池将在某一点或另一点耗尽。
我感兴趣地观察了Reactive模型如何像篝火一样在Spring生态系统中传播,尽管我选择站在一边。恕我直言,反应式有几个缺点:
- 编写(和阅读!)反应式代码的思维方式与编写传统代码的思维方式非常不同。我愿意承认改变心态只需要时间,持续时间取决于每个开发人员。
- 尽管真正的开发人员不会调试,但我知道很多人会调试-包括我自己。由于上述线程切换的魔力,要跟踪一段代码及其相关的状态并不容易。这需要足够的工具,例如带有相关插件的 IntelliJ IDEA 。
- 最后,出于相同的原因,传统的堆栈跟踪也无济于事。一些黑魔法可以绕开它。但是,这不是为了胆小者。有关选项的完整列表,请查看此文档。
Kotlin语言提供了Reactive方法的替代方法:协程。简而言之,当使用suspend关键字时,Kotlin编译器会在字节码中生成一个有限状态机。好处是在协程块中调用的函数看起来像是顺序执行的,尽管它们是并行执行的-更确切地说,取决于确切的范围,有可能会执行。
Project Loom和虚拟线程
Reactive模型和Kotlin协程都在客户端代码和JVM线程之间添加了一个额外的抽象层。框架/库的职责是动态地将一个映射到另一个。问题的症结在于JVM线程是OS线程的薄包装:请记住,OS线程创建起来很昂贵,并且数量限制为数千个。
Project Loom的目标是实际上将JVM线程与OS线程解耦。
当我第一次意识到该倡议时,其想法是创建一个称为Fiber(线程,Project Loom,您能抓住麻烦吗?)的抽象。一个Fiber责任是让一个操作系统线程,使其运行代码,释放回池,就像无栈一样。
当前的建议有很大的不同:Fiber它没有使用新的类,而是重新使用了Java开发人员非常熟悉的一个类- java.lang.Thread!
因此,在新的JVM版本中,某些Thread对象可能是重量级的并映射到OS线程,而另一些对象可能是虚拟线程。
Project Loom发布的后续影响
主要问题是,既然JVM API提供了对OS线程的抽象,那么其他抽象(例如响应式和协程)又会变成什么样呢?我对预测不满意,但以下是Reactive /协程背后的公司可能采取的一些态度:
- 正面态度,他们意识到自己的框架不再带来任何附加值,而只是重复。他们停止了开发工作,仅向现有客户提供维护版本。他们帮助说客户迁移到新的ThreadAPI,一些帮助可能是以付费咨询的形式。
- 反面态度,他们在各自的框架中投入了大量的精力之后,他们决定继续进行,好像什么也没有发生。例如,Spring框架负责实际设计一个共享的Reactive API,称为Reactive Streams,没有Spring依赖项。当前有两种实现,RxJava v2和Pivotal的Project Reactor。另一方面,JetBrains宣传Kotlin的协程是并行运行代码的最简单方法。
- 中间态度。这两个框架都将继续其生命,但是会将它们各自的基础实现更改为使用虚拟线程。
由于沉没成本的谬误,排在第一位的可能性极小:销售和市场营销将努力保持其“竞争优势”-无论在他们眼中意味着什么。尽管有些工程师出于相同的原因希望保留现有代码,但其他一些工程师则将努力使用新的API。因此,我也不相信第二名也会发生。但是,我认为这两个工程派之间都发挥着力量,然后它们与市场营销/销售之间将在#3之间找到平衡。
结论
Project Looms将现有的Thread实现方式从OS线程的映射更改为可以表示此类线程或虚拟线程的抽象。就其本身而言,这是一个有趣的举动,它在一个平台上历来比创新更重视向后兼容性。与其他最新的Java版本相比,此功能是真正的游戏规则改变者。一般而言,开发人员应尽快开始熟悉它。打算学习Reactive和协程的开发人员可能应该退后一步,并评估他们是否应该学习新的ThreadAPI- 是否需要。
翻译原文
https://blog.frankel.ch/project-loom-reactive-coroutines/
扩展阅读
Project Loom地址: https://github.com/openjdk/loom
Project Loom现有状态: http://cr.openjdk.java.net/~rpressler/loom/loom/sol1_part1.html
Project Loom:Reactive模型和协程进行时(翻译)的更多相关文章
- Unity 协程运行时的监控和优化
我是快乐的搬运工: http://gulu-dev.com/post/perf_assist/2016-12-20-unity-coroutine-optimizing#toc_0 --------- ...
- 闭包(closure)与协程共用时要注意的事情
闭包是一种能够让你用非常舒服的方式来编程的小技巧,Go也支持闭包. 假设从来没有接触过闭包,想在一開始就弄懂什么是闭包(closure)是非常困难的,就像递归一样,直到你真正写过.用过它,你才干真正的 ...
- 终结python协程----从yield到actor模型的实现
把应用程序的代码分为多个代码块,正常情况代码自上而下顺序执行.如果代码块A运行过程中,能够切换执行代码块B,又能够从代码块B再切换回去继续执行代码块A,这就实现了协程 我们知道线程的调度(线程上下文切 ...
- 图解协程调度模型-GMP模型
现在无论是客户端.服务端或web开发都会涉及到多线程的概念.那么大家也知道,线程是操作系统能够进行运算调度的最小单位,同一个进程中的多个线程都共享这个进程的全部系统资源. 线程 三个基本概念 内核线程 ...
- Java协程实践指南(一)
一. 协程产生的背景 说起协程,大多数人的第一印象可能就是GoLang,这也是Go语言非常吸引人的地方之一,它内建的并发支持.Go语言并发体系的理论是C.A.R Hoare在1978年提出的CSP(C ...
- 从Erlang进程看协程思想
从Erlang进程看协程思想 多核慢慢火了以后,协程类编程也开始越来越火了.比较有代表性的有Go的goroutine.Erlang的Erlang进程.Scala的actor.windows下的fibr ...
- 第十天 多进程、协程(multiprocessing、greenlet、gevent、gevent.monkey、select、selector)
1.多进程实现方式(类似于多线程) import multiprocessing import time,threading def thread_run():#定义一个线程函数 print(&quo ...
- 协程coroutine
协程(coroutine)顾名思义就是“协作的例程”(co-operative routines).跟具有操作系统概念的线程不一样,协程是在用户空间利用程序语言的语法语义就能实现逻辑上类似多任务的编程 ...
- day-5 python协程与I/O编程深入浅出
基于python编程语言环境,重新学习了一遍操作系统IO编程基本知识,同时也学习了什么是协程,通过实际编程,了解进程+协程的优势. 一.python协程编程实现 1. 什么是协程(以下内容来自维基百 ...
随机推荐
- Java Serializable(序列化)的总结
1.序列化是干什么的? 简单说就是为了保存在内存中的各种对象的状态(也就是实例变量,不是方法),并且可以把保存的对象状态再读出来.虽然你可以用你自己的各种各样的方法来保存object states,但 ...
- 计划任务工具-windows
计划任务工具根据自己设定的具体时间,频率,命令等属性来规定所要执行的计划. 代码 # -*- coding: utf-8 -*- """ Module implement ...
- 二维DCT变换 | Python实现
引言 最近专业课在学信息隐藏与数字水印,上到了变换域隐藏技术,提到了其中的DCT变换,遂布置了一个巨烦人的作业,让手动给两个\(8\times8\)的矩阵做二维DCT变换,在苦逼的算了一小时后,我决定 ...
- PMP 冲!|项目整合管理
0x00概述 项目管理包括识别.定义.组合.统一与协调各项目管理过程组的过程及项目管理活动.包括在各个项目冲突的目标与方案之间进行权衡和选择. 整合管理包括进行如下选择: 资源分配: 平衡竞争性需求: ...
- 当微信小程序遇到云开发,再加上一个类似 ColorUI 的模板,人人都能做小程序了
作为一个 Java 程序员,早就想尝试一把微信小程序,但是一直苦于没有想法,再加上做一个漂亮的页面实在不太擅长. 由于自己比较喜欢历史,经常看历史方面的书.在一次梳理中国现有的朝代时,突然想到,要是可 ...
- Rocket - util - HeterogeneousBag
https://mp.weixin.qq.com/s/5hNM4yeQjaLvAJzgMG9PGQ 介绍HeterogeneousBag的实现. 1. 基本介绍 一个口袋(bag ...
- 带你学够浪:Go语言基础系列-环境配置和 Hello world
文章每周持续更新,原创不易,「三连」让更多人看到是对我最大的肯定.可以微信搜索公众号「 后端技术学堂 」第一时间阅读(一般比博客早更新一到两篇) 前面几周陆陆续续写了一些后端技术的文章,包括数据库.微 ...
- Java实现 LeetCode 172 阶乘后的零
172. 阶乘后的零 给定一个整数 n,返回 n! 结果尾数中零的数量. 示例 1: 输入: 3 输出: 0 解释: 3! = 6, 尾数中没有零. 示例 2: 输入: 5 输出: 1 解释: 5! ...
- Mybatis缓存及延迟加载策略
一:引言 通过前面几篇的文章介绍了Mybatis的一对一.一对多.多对多关系的配置及实现,可是大家发现了吗?在执行关联查询的时候,直接会把当前查询的主表里包含的副表也查询后封装到对象里,其实在实际开发 ...
- 读取Excel文件,抛出类似Cleaning up unclosed ZipFile for archive D:\project\myTest\autoAppUI\excelMode\用例模板2.xlsx 错误解决
读excel用例的时候总报这个错误,一直不知道什么原因~~~~~~~~~~ 今天突然顿悟了,原来是读excel的时候用到了文件流,我在读文件的方法里加了流关闭的操作,完美解决报错