加入收藏 | 设为首页 | 会员中心 | 我要投稿 西安站长网 (https://www.029zz.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 移动 > 正文

Go语言出现后,Java还是好选择吗?

发布时间:2019-11-02 14:35:56 所属栏目:移动 来源:梁希
导读:副标题#e# 随着大量新生的异步框架和支持协程的语言(如Go)的出现,在很多场景下操作系统的线程调度成为了性能的瓶颈,Java也因此被质疑是否不再适应最新的云场景了。4年前,阿里JVM团队开始自研Wisp2,将Go语言的协程能力带入到Java世界。既享受Java的丰富

我们不妨看一个阻塞的系统调用futex的热点分布:

Go语言出现后,Java还是最佳选择吗?

可以看到上面的热点中有大量涉及调度的开销。我们来看过程:

  1. 调用系统调用(可能需要阻塞);
  2. 系统调用确实需要阻塞,kernel需要决定下一个被执行的线程(调度);
  3. 执行上下切换。

因此,上面2个误区与多线程的开销都有一定因果关系,但是真正的开销来源于线程阻塞唤醒调度。

综上,希望通过线程模型来提升web server性能的原则是:

  1. 活跃线程数约等于CPU个数
  2. 每个线程不太需要阻塞

文章后续将紧紧围绕这两个主题。

为了满足上述两个条件,使用eventloop+异步callback的方式是一个极佳的选择。

异步与协程的关系

为了保持简洁,我们以一个异步服务器上的Netty写操作为例子(写操作也存在阻塞的可能):

  1. private void writeQuery(Channel ch) { 
  2.   ch.write(Unpooled.wrappedBuffer("query".getBytes())).sync(); 
  3.   logger.info("write finish"); 

这里的sync()会阻塞线程。不满足期望。由于netty本身是一个异步框架,我们引入回调:

  1. private void writeQuery(Channel ch) { 
  2.   ch.write(Unpooled.wrappedBuffer("query".getBytes())) 
  3.     .addListener(f -> { 
  4.       logger.info("write finish"); 
  5.     }); 

注意这里异步的write调用后,writeQuery会返回。因此假如逻辑上要求在write后执行的代码,必须出现在回调里,write是函数的最后一行。这里是最简单的情形,如果函数有其他调用者,那么就需要用CPS变换。

需要不断的提取程序的"下半部分",即continuation,似乎对我们造成一些心智负担了。这里我们引入kotlin协程帮助我们简化程序:

  1. suspend fun Channel.aWrite(msg: Any): Int = 
  2.     suspendCoroutine { cont -> 
  3.         write(msg).addListener { cont.resume(0) } 
  4.     } 
  5.  
  6. suspend fun writeQuery(ch: Channel) { 
  7.     ch.aWrite(Unpooled.wrappedBuffer("query".toByteArray())) 
  8.     logger.info("write finish") 

(编辑:西安站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读