Async, eventloop-reactor (js, grpc,vertx)

需求: 如何写个异步调用,以后能力高了,写出个异步框架呢? 

今天我来谈谈自己的想法,也是为以后尝试写异步框架奠定些基础。

第一,异步是什么东西呢? 我的理解异步就是(1) 不等待,直接返回 (2)对于异步框架,比如vertx,一般会有 callback。(3)对于异步框架来说,主线程不会终止异步线程。(4) 对于单线程来说,比如js,会形成event queue

好了,其实掌握异步的线程模型,得好好掌握netty reactor线程模型。

第二, java 如何写个异步调用的? 听起来很简单,异步嘛,callback就可以了。一开始我确实是这么想的,因为我最近vertx 框架想多了,一个简简单单的callback 就实现了异步调用。 但是java的callback 却实现不了异步。至于js callback 异步,我们后面分析。那我们怎么写java 异步呢? 异步的本质是什么呢,为什么我写的callback代码是同步,别人写的callback代码就是异步呢?  首先得清楚的知道以下几点。 

     (1) 根据李林锋的文章,jdk 1.0 到jdk 1.3 , java 的 IO 类库都非常原始,很多unix 网络编程中的概念或者接口再IO类库中都没有体现,例如 Pipe, channel,Buffer,和 Selector。 jdk1.4 时候,出现了Nio 的包,提供了进行异步的API 和类库,比如 byteBuffer,Pipe, serverSocketChannel 和socketChannel,多路复用的selector。按照我的理解,这就表明,jvm 底层 再jdk 1.0 和 jdk 1.3 就不支持异步的操作。

      (2)  java 的主线程 和 子线程之间的关系。比如setDaemon(true),主线程会终止子线程,尽管子线程还没有执行完。 Thread.join(). 主线程会等待子线程执行完了之后,才会执行主线程。当我们什么都不设置的时候,主线程和子线程之间 是不互相影响的。vertx 就是这样的异步框架。vertx 的callback 都是一个个handler。

     (3) 线程调用,底层由系统来决定的,比如java 里面的native 方法。linux fork 一个子线程和windows fork 子线程可能是不一样的。Nio 的线程模型是如何执行的,需要操作系统的线程调用。

那我要是想写个java 异步程序是不是很简单? 不用callback,直接 new thread(()-> {system.out,println("async invoking")}).start()。 Thread 里面的run 方法就会异步的执行. 请看下图, 是不是很简单? 但是我会问,为什么执行线程这块不是同步呢? 都由主线程来执行呢,可是当new 一个新的线程之后,就会告诉主线程,你继续执行把,新线程里面的东西,我自己的线程栈执行就可以了,你不用管我。这就是为什么scheduledthreadPool, fixedthreadPool,cachethreadPool等,这些都是异步的,由新的线程池来执行,主线程该干啥干啥去。这就是异步!至于为什么 新new thread就是异步的,我觉得这个得看背后的 jvm 怎么实现的,jvm 是如何调用操作系统的线程来做异步代码执行的。 new thread start方式调用的是native() 方法:

private native void start0();

第三: 那是不是 我就可以写异步框架,比如通信的server 端了? 不管是 grpc http2协议,vertx tcp 通信和http 协议。我们还得想想 性能问题,我可以用socket 通信简单写个异步的server 端出来,但是性能呢? 可以接多少个客户端的请求呢? 

那我们再等等,需要了解下面的 线程模型的演变,note: 个人觉得底层的操作,比如多路复用,还是需要操作系统底层的支持的,现在是多核多CPU,多线程的 硬件设备。 但是底层到底是怎么支持,我确实不太清楚,但是不妨碍我们继续往下走。

(1).  

传统的java BIO web 模型,比如tomcat, 一个请求就会由一个线程进行阻塞的处理。这样的线程模型支持的并发量并不是很高,二是线程阻塞,很容易导致服务端的crash 掉。 而且我们不能同时创建这么多线程来阻塞执行。

(2).   

看下上面的图,是不是很明了? 由于(1) 图是来一个请求,就会创建一个新的线程,这个弊端很是明显,那么(2) 图,就使用一个线程池的方式来做,线程池控制总的线程数量。因此避免了每个请求都会创建一个新线程从而耗尽资源。 但是由于底层仍是采用了同步阻塞的方式处理,从而仍然不能解决性能, 可靠性, 可维护性等问题。

(3)


jdk 5之后,java 底层通信发生了变化,许多的Nio的出现,使得 java 线程 不再是以阻塞的方式调用,异步调用,多路复用的方式开始出现。我们看上面的线程模型,selector 多路复用的选择一个就绪的cahnnel,然后dispatcher 分发,给 reactor thread pool handler 异步执行。然后异步处理完成之后,再由selector 将结果通过channel 给客户端。但是问题是reactor thread pool 线程也会越积越多。我觉得这样的线程模型在有限的线程资源下,利用的越来越合理,但是真当许多的并发流量来的时候,还是要扩容机器的。

(4)

multiple reactor 模式, 有了mainReactor 和 subReactor, mainReactor 主要负责 accept, subReactor 则负责 read, send等操作。其中由read 等操作,再进一步给thread pool 来操作。 整个线程模型是越来越有效率。比最初的好处有哪些呢?

 1. 每个client 请求 不是新new thread 线程来处理,而是有acceptor 通过多路复用 统一的处理。

2. task 处理,比如各种handler 不再同步的处理,而是采用异步的线程池的方式处理。此外各个线程池分工合作,高效很多。

但是此处,我有一点点不理解的地方,selector 的多路复用,应该只用在了acceptor 和 channel 的状态等, 真正的任务处理,也还是要线程池里面的线程去执行,然后通过回调返回给selector,返回给 channel。 这样不会有阻塞,线程池来管理,各个部分分工合作。

第四步: 好了,当我们大致了解这些东西之后,我们就可以选择一个框架来写异步框架了,当然首选的还是netty,grpc 使用的netty4.X 版本的,支持http2 的标准协议。这个框架怎么写,需要以后有时间尝试写个rpc 异步框架。但是呢,介绍到这里,我觉得应该初步明白应该从哪里研究哪里动手了。

最后我还想简单的介绍下 js 的 eventloop 和 vertx 的eventloop。

首先看js 的:

js是单线程的,HTML5提出Web Worker标准,但是子线程完全受主线程控制,且不得操作DOM。从而说js 还是单线程的。js 的eventloop 就非常的简单,不像java netty。

这个简单把,上面图来自与Philip Roberts的演讲《Help, I'm stuck in an event-loop》

你看stack 线程栈按顺序执行着,有回调(callback),比如ajax, 我就把回调放到下面的callback queue 里面,然后等主线程栈的代码执行完了之后呢,就开始执行callback queue 里面的 onclick,onload 等等callback。 我个人觉得里面异步执行是有异步执行的线程的,将异步执行的结果放到queue 队列就结束了,因此我觉得主线程是eventloop线程,但是异步执行的线程也是不可避免的,不然谁来执行ajax 请求呢? 就像set timer  一样,我觉得还是有timer 这样的线程来执行的。

那vertx 呢?  这个vertx 线程模型也是由eventloop来的。当设置vertx.deploy(verticle).setWorker(true)的时候,在每个verticle里面的代码执行都是eventloop 主线程执行的,里面每个函数的callback,都是有子线程,也就是worker线程来执行的,但是verticle里面是没有race condition 关系的,也就是说同一时间,只会有一个线程执行代码,我也很好奇这种的执行方式是如何保证的。 我觉得是每个 callback 就是个callback, 然后像js 那样,再eventloop 主线程执行完之后,才从handler queue 取出线程,一个一个执行,此时执行的时候,就是worker 线程。

这些框架到处都是神奇的地方,如果想完全理解,只有自己写个异步框架就好理解了。不然也会许多不明白的地方,希望我有机会自己写个异步框架,这才是霸气所在把。另外有些地方还是值得以后慢慢研究,研究越深,就会有豁然开朗感觉。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,265评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,078评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,852评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,408评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,445评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,772评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,921评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,688评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,130评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,467评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,617评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,276评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,882评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,740评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,967评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,315评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,486评论 2 348

推荐阅读更多精彩内容