为什么Java坚持多线程不选择协程?
从java被发明的第一天起,就被定义为一个多线程的网络编程语言。Java最大特点并不是跨平台,而是它的多线程模型(那时候的C++中,并没有我们现在看到的thread,C#还没有出来)。因为近二十年的软件行业的增长主要来自网络编程,网络编程最常见的模型就是client/server, 也就是所谓的C/S,这种编程模型在服务器端需要同时接受客户端的请求,也就是说要有很好的并发特性--这个特性主要依赖多线程来实现。而java的主战场就是服务器端编程。所以多线程对java是极为重要,不可或缺的一环。
当我们希望引入协程,我们想解决什么问题。我想不外乎下面几点:
节省资源,轻量,具体就是:节省内存,每个线程需要分配一段栈内存,以及内核里的一些资源节省分配线程的开销(创建和销毁线程要各做一次syscall)节省大量线程切换带来的开销与NIO配合实现非阻塞的编程,提高系统的吞吐使用起来更加舒服顺畅(async+await,跑起来是异步的,但写起来感觉上是同步的)我们分开来讲下。
先说内存。拿Java Web编程举例子,一个tomcat上的woker线程池的最大线程数一般会配置为50~500之间(目前springboot的默认值给的200)。也就是说同一时刻可以接受的请求最多也就是这么多。如果超过了最大值,请求直接打失败拒绝处理。假如每个线程给128KB,500个线程放一起的内存占用量大概是60+MB。如果真的有瓶颈,也许CPU,IO,带宽,DB的CPU等会有瓶颈,但这点内存量的增幅对于动辄数个GB的Java运行时进程来说似乎并不是什么大问题。
为什么许多原本的Java项目都试图用go进行重写开源?
有人的地方就有政治,对互联网公司来说,重构是政治斗争和裁员的重要手段。
给你举个例子吧。前同事A之前在某家公司做运维主管,公司是自建的机房,包括部署,监控,故障自愈,数据库等等平台有关的一切,都是他一手搭起来的,没有人比他更了解。新来的开发经理不服,非要自己来部署,导致出了大故障,等待跑路,A出马几分钟搞定。于是公司只能继续供着他,工资奖金啥的都给的多,偶尔他请假了,有问题也只能等他回来,时间长了,领导哪能容忍这种事?
正好这时候云服务器强势上位了,公司领导拍板决定全面上云,让其他技术也参与,担心这位仁兄不配合,承诺迁移完后有奖金。几个月后迁移完成了,Redis、MongoDB、MySQL使用云托管的,先废一半。部署的时候由开发一起参与CI/CD流程,这时候他的重要性再次被减弱,没多久待不下去了。
放到开发重构也是一样的道理,公司的业务架构都是老员工搞起来的,老员工岂不是会恃宠而骄?那新人怎么上位?
所以不要觉得有一技之长会越来越吃香,公司领导不会让一家独大的局面长久的,会威胁到他。
个人觉得应该是三个主要原因吧。
一. 体积可以明显缩小,部署更简单
因为容器服务越来越主流,这到不是说Java不能在云原生环境使用,现在云原生里的微服务模式,主流编程语言还是Java,只是,依赖于JDK平台确实让容器镜像体积大了很多!大部分情况下,微服务本身jar的体积(包括各种依赖的flat jar)也与JDK本身的体积相差无几(甚至不及)。在多个服务情况下,拉取镜像的成本就高很多,虽然分层存储可以有效降低存储容量,但这也依赖所有微服务需要相同的镜像基座(部署好JDK),对于不同厂商的微应用(服务)情况不一定乐观。
Golang在这部分表现好很多,虽然打包后的Binary也不小(相比于C),但它包含运行时支持及静态链接,非常独立(单体程序易于部署),体积相比Java的服务,总体要小很多。
二. 开发难度不大
后端应用服务最重要的是稳定,Java之所以能长时间占据后端开发市场份额,也是因为其异常及GC机制能够平衡好程序开发难度和程序质量这两个矛盾体。而Golang也引入了GC,开发难度也不高(并不比Java难),不需要特别优秀的能力也能写出健壮的后端应用。
三. 语言发展的必然结果
现在越来越多的人开始使用Golang写后端应用。当你进入这个领域,你就会发现,你需要的各种框架,基础设施基本上都是在重复写一遍其他已经进入该领域的语言的各种框架和基础库😄 这是工程本身决定的,到不一定是抄Java。记得Nodejs刚出来的时候,借助于V8强大的性能,大前端的各种开发工具,框架如雨后春笋般发展起来,但也基本上是走了一遍其他语言(尤其是Java)的路。
不同语言在发展过程中,总会进入其他“先入语言”的领域,然后也会再走一遍人家的路,完善和建立自身在该领域的生态。这是后发语言发展的必经之路!