最实用的golang调试bug 以及性能问题的实践方法

一、流?I/O操作? 阻塞?

(1) 流

(2) I/O操作

(3) 阻塞

二、解决阻塞死等待的办法

阻塞死等待的缺点

办法一:非阻塞、忙轮询

办法二:select

办法三:epoll

三、epoll?

四、epoll的API

(1) 创建EPOLL

(2) 控制EPOLL

(3) 等待EPOLL

(4) 使用epoll编程主流程骨架

五、epoll的触发模式

(1) 水平触发

(2) 边缘触发

六、简单的epoll服务器(C语言)

(1) 服务端

(2) 客户端

一、流?I/O操作? 阻塞?

(1) 流

可以进行I/O操作的内核对象

文件、管道、套接字……

流的入口:文件描述符(fd)

(2) I/O操作

所有对流的读写操作,我们都可以称之为IO操作。

当一个流中, 在没有数据read的时候,或者说在流中已经写满了数据,再write,我们的IO操作就会出现一种现象,就是阻塞现象,如下图。

最实用的golang调试bug 以及性能问题的实践方法

最实用的golang调试bug 以及性能问题的实践方法

(3) 阻塞

最实用的golang调试bug 以及性能问题的实践方法

​ 阻塞场景: 你有一份快递,家里有个座机,快递到了主动给你打电话,期间你可以休息。

最实用的golang调试bug 以及性能问题的实践方法

非阻塞,忙轮询场景: 你性子比较急躁, 每分钟就要打电话询问快递小哥一次, 到底有没有到,快递员接你电话要停止运输,这样很耽误快递小哥的运输速度。

阻塞等待

空出大脑可以安心睡觉, 不影响快递员工作(不占用CPU宝贵的时间片)。

非阻塞,忙轮询

浪费时间,浪费电话费,占用快递员时间(占用CPU,系统资源)。

很明显,阻塞等待这种方式,对于通信上是有明显优势的, 那么它有哪些弊端呢?

二、解决阻塞死等待的办法

阻塞死等待的缺点

最实用的golang调试bug 以及性能问题的实践方法

​ 也就是同一时刻,你只能被动的处理一个快递员的签收业务,其他快递员打电话打不进来,只能干瞪眼等待。那么解决这个问题,家里多买N个座机, 但是依然是你一个人接,也处理不过来,需要用影分身术创建都个自己来接电话(采用多线程或者多进程)来处理。

​ 这种方式就是没有多路IO复用的情况的解决方案, 但是在单线程计算机时代(无法影分身),这简直是灾难。

那么如果我们不借助影分身的方式(多线程/多进程),该如何解决阻塞死等待的方法呢?

办法一:非阻塞、忙轮询

最实用的golang调试bug 以及性能问题的实践方法

while true {
    for i in 流[] {
        if i has 数据 {
            读 或者 其他处理
        }
    }
}

非阻塞忙轮询的方式,可以让用户分别与每个快递员取得联系,宏观上来看,是同时可以与多个快递员沟通(并发效果)、 但是快递员在于用户沟通时耽误前进的速度(浪费CPU)。

办法二:select

 

最实用的golang调试bug 以及性能问题的实践方法

我们可以开设一个代收网点,让快递员全部送到代收点。这个网店管理员叫select。这样我们就可以在家休息了,麻烦的事交给select就好了。当有快递的时候,select负责给我们打电话,期间在家休息睡觉就好了。

但select 代收员比较懒,她记不住快递员的单号,还有快递货物的数量。她只会告诉你快递到了,但是是谁到的,你需要挨个快递员问一遍。

while true {
    select(流[]); //阻塞

  //有消息抵达
    for i in 流[] {
        if i has 数据 {
            读 或者 其他处理
        }
    }
}

办法三:epoll

最实用的golang调试bug 以及性能问题的实践方法

epoll的服务态度要比select好很多,在通知我们的时候,不仅告诉我们有几个快递到了,还分别告诉我们是谁谁谁。我们只需要按照epoll给的答复,来询问快递员取快递即可。

完整全文:http://www.golang.ren/article/5921



上一篇:竟然还有人认为Redis只有get set那样简单?!


下一篇:Java filter中的chain.doFilter详解