2010-04-25

Netty/NIO和多线程杂谈.

 
  近来貌似无所事事.
 
  能写的东西也不多.

  在新单位遇到个"好领导",于是倒也乐得清闲,没事就翻翻Netty的代码.
  虽然,看来也没什么大的收获.
  但至少有事情做.

  当然,眼下的事情貌似应该是考虑试用期过之后怎么办了.
  毕竟,按照目前的情况,继续被冷处理的话,试用期是过不了的.
  除非上上级给面子.

  这些都是后话了.
 
  这里扯两句Netty这东西.

  说是Netty,但基本还是NIO的内容吧.

  以前单纯美好地认为NIO也不过如此.
  也不过是轮询select各个socket.

  但了解过之后才知道,这其实是跟平台相关的.
  准确点说,这是跟jvm的配置有关.
  
  默认地,JVM或根据所在的平台选择相应的nio provider.
  在linux kernel 2.6下,这个provider使用的select策略是epoll.

  当然,这是文档的说法.
  具体它怎么用epoll是jvm的事情了.
  
  要从openjdk里找出来,也不容易.
  
  顺手去翻了下这个epoll的一些资料.
  稍微有点明白大概的实现机制.

  以前的poll确实是轮询处理的.
  而epoll用高级点的话说,就是事件机制,通过注册相应的事件,来响应io.
  减少无谓的时间消耗.

  看了一些资料和代码的结论是,这种事件也是通过回调完成的.

  猜测可能kernel在处理io的时候被插入了一些回调函数.
  当io ready的时候触发这些函数,通知注册事件.

  这点有写ajax的味道.
  或者说用ajax模拟的server push.方式.
  
  当然,明显可能是后者模仿前者.

  这样做的结果就是cpu从io等待中解脱出来了.
  等待io的事情交给了最底层的io硬件.
  
  反正都是要等的,就不在乎等完之后多做点事情.

  这里想起来线程复用的问题.

  Java里面有个cachedthradpool之类的东西.
  说是可以线程复用.(Excutor的概念).

  进Java代码里看来下,也不过是将线程进队列,依次start.
  作用貌似只是保证同时运行的线程不过超过一定数量.

  当时很好奇,所谓线程复用怎么做的.

  于是就尝试写了个thread去跑,跑的内容是一个植入的回调函数.
  让它跑两次.中间替换一次植入函数.

  结果当然是抛异常.

  顺便说句,在做上面这件事情的时候无比渴望有lambda支持.
  省得写多几行代码.

  看来下Thread的start,里面会有个标记为看是否是新创建的线程.
  一个threadstate的int型.
  
  在java里并没有看到有改动这个值的,想想,应该是在native里实现的.

  总是,大概是启动之后这个值就被改变了吧.
  于是当再次调用语言级别的start之后,异常就抛出了.

  也就是说,当一个线程执行完之后,自然是交给gc了.
  因为从java来看的话,并不能使它再次运行.

  当然,也许cachedthreadpool是用来native的方法去改变threadstate.
  这自然也可以.

  不过要从纯Java角度来看的话,也不是不可能,只不过要做的事情比较多罢了.

  考虑对run()这个thread的实现做一个回调植入.
  比如
  public void run()
  {
     while(true)
     {
       this.getFunction().excute();
     }
  }
  
  这样,很roughly地,就让一个线程不死了.
  也就能实现所谓的reused了.

  当然,这里能改善的地方还很多.
  比如对this.getFunctin()做个改变,让他是从一个queue里pop出来的.
  这样,在while就变成看queue是否为空来选择是执行呢,还是wait一下.

  愿意的话,还可以在queue空的时候,把thread注册到一个free queue里.
  然乎run里直接wait()或者yeild()或者sleep()退出时间片的竞争.
  当需要的时候,再从queue里激活.

  想想,这个memory pool 其实是差不多的道理.

  说了这么多,貌似跟Netty没太大的关系.

  其实就目前的进度来说,netty还真没什么可以说的.

  总的来说,这是一个流水作业的io框架.

  有一个sendUpstream和sendDownstream,来分别处理上行下行的ChannelEvent.
  event在一个pipelien里流动.
  自上而下,自下而上.

  pilieline其实就是一个由ChannelHandler组成的queue,或者说list.
  当然,pileline也不一定会把io在chain里流过handler.
  有时候也会通过ChannelHandlerContext这一类的东西改变流向.

  ChannelHandlerContext里面其实也是ChannelHanlder.
  只不过带来一些附属品而已.
  也就是说,其实它只是一个有状态的channelhandler.

  具体的read write操作最后归结到sendUpstream和sendDownstream里.
  当然,最后还是通过NIO的selector来做的.

  不过这个过程是由一群IOWorker线程来完成传递的.

  大致浏览量下,boss线程组貌似是专门用来accpet的.ioworker是用来读写的.
  这个目前不确定.
  不过也有道理.
  因为貌似这两个线程组netty是尝试分到不同的cpu上面的.
  
  具体还是未知.

没有评论:

发表评论

爽文

去看了好东西. 坦白说,多少是带着点挑刺的味道去的. 毕竟打着爱情神话和女性题材的气质,多多少少是热度为先了. 看完之后倒是有些新的想法. 某种程度上来说,现在的年轻人或者说声音就像小叶. 只要说点贴心的话就能哄好. 也是那种可以不用很努力了. 留在自己的舒适区避难所小圈子抱团就...