Handler源码分析之epoll机制

分析epoll机制之前我们需要先明确一个概念什么是阻塞和非阻塞?

举个例子,假设你要收个快递,但你不知道快递小哥什么时候送,你又没有其他事可做,那么你可以去睡觉了(释放cpu资源),因为你知道快递小哥到了会打电话通知你,这个睡觉的状态就是阻塞

同样,你要收个快递,但你不知道快递小哥什么时候送,但你放心不下这件事你不选择去睡觉,你每分钟都给快递小哥打电话问他到了没,你一直打电话询问这个状态就是非阻塞式忙轮询,虽然最终都收到了快递,但后者会很累(cpu一直在运行)java并发编程中的CAS也是这种原理。

而阻塞是一个和 I/O 相关的概念,这涉及一个操作系统级的操作epoll_wait,当读取磁盘文件时会有内存速度不匹配的问题,中间需要有个缓存过程,是从磁盘读到缓存,缓存满了,再从缓存中读数据,等待缓存满的时候就需要阻塞住先不读取。

再举个例子,当前有n个I/O事件,我们如何处理多个流?

没有阻塞概念的话,如下(是一段伪代码):

while(true){
   for(i -> stream[]){
       // 一直询问我可以读了吗?
       if i has data{
           read data until unalivaible     
       }
   }

}

这种方式下,当所有的流都没数据的这段时间里,cpu只能一直跑for循环,但又没有数据可读,所以cpu一直在空转,耗费cpu资源而没有任何意义,那怎么解决这个问题呢?

阻塞就出现了:

while(true){
   //select是个Linux系统级操作,他会一直阻塞直到其中有一个或多个流可以读,再去执行下面的代码
   select(stream[])
   for(i -> stream[]){
       // 一直询问我可以读了吗?
       if i has data{
           read data until unalivaible     
       }
   }

}

但是这个方式并不能确切的知道有几个流可读,我们只能无差别的去轮询所有的流,那怎么处理这个缺陷呢?随着Linux系统的升级,今天的主角epoll就出现了:

while(true){
   //select是个Linux系统级操作,他会一直阻塞直到其中有一个或多个流可以读,再去执行下面的代码
   active_stream = epoll_wait(stream[])
   for(i -> active_stream[]){
       read data until unalivaible     
   }

}

epoll可以过滤出可以进行读写的流,而不用我们再去轮询了,此时我们对所有流的处理都是有意义的。

epoll是Linux内核中的一种可扩展IO事件处理机制。大量应用程序请求时能够获得较好的性能。

下面是几个epoll相关的几个方法:

int epoll_create(int size);
//创建一个epoll的句柄,size用来告诉内核需要监听的数目一共有多大

int epoll_ctl(int epfd,int op,int fd,struct epoll_event *event)
//epoll的事件注册函数

int epoll_wait(int epfd,struct epoll_event * events,int maxevents,int timeout)
//参数events用来放从内核得到事件的集合,maxevents告知这个events有多大,这个maxevents的值不能
//大于创建epoll_create()时的size,timeout是超时时间(毫秒,0会立即返回,-1将不确定,也有说法是永久阻塞)

到此epoll是什么大家已经有了基本概念和认知,下面再结合我们熟悉的Handler看看在Handler中是如何使用的:

MessageQueue.java
 
 //epoll的句柄,通过他能找到对应的epoll
 private long mPtr;
 MessageQueue(boolean quitAllowed) {
        mQuitAllowed = quitAllowed;
        //native层去创建epoll
        mPtr = nativeInit();
 }
 
  //以下是epoll相关的native方法
  private native static long nativeInit();//会调用epoll_create()
  private native static void nativeDestroy(long ptr);
  @UnsupportedAppUsage
  private native void nativePollOnce(long ptr, int timeoutMillis); //会调用epoll_wait(),这个函数里timeout就是这里传进去的
  private native static void nativeWake(long ptr);  //唤醒阻塞
  private native static boolean nativeIsPolling(long ptr);
  private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events);

epoll的了解就先到此为止了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值