-
最实用的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操作就会出现一种现象,就是阻塞现象,如下图。
(3) 阻塞
阻塞场景: 你有一份快递,家里有个座机,快递到了主动给你打电话,期间你可以休息。
非阻塞,忙轮询场景: 你性子比较急躁, 每分钟就要打电话询问快递小哥一次, 到底有没有到,快递员接你电话要停止运输,这样很耽误快递小哥的运输速度。
阻塞等待
空出大脑可以安心睡觉, 不影响快递员工作(不占用CPU宝贵的时间片)。
非阻塞,忙轮询
浪费时间,浪费电话费,占用快递员时间(占用CPU,系统资源)。
很明显,阻塞等待这种方式,对于通信上是有明显优势的, 那么它有哪些弊端呢?
二、解决阻塞死等待的办法
阻塞死等待的缺点
也就是同一时刻,你只能被动的处理一个快递员的签收业务,其他快递员打电话打不进来,只能干瞪眼等待。那么解决这个问题,家里多买N个座机, 但是依然是你一个人接,也处理不过来,需要用影分身术创建都个自己来接电话(采用多线程或者多进程)来处理。
这种方式就是没有多路IO复用的情况的解决方案, 但是在单线程计算机时代(无法影分身),这简直是灾难。
那么如果我们不借助影分身的方式(多线程/多进程),该如何解决阻塞死等待的方法呢?
办法一:非阻塞、忙轮询
while true {
for i in 流[] {
if i has 数据 {
读 或者 其他处理
}
}
}
非阻塞忙轮询的方式,可以让用户分别与每个快递员取得联系,宏观上来看,是同时可以与多个快递员沟通(并发效果)、 但是快递员在于用户沟通时耽误前进的速度(浪费CPU)。
办法二:select
我们可以开设一个代收网点,让快递员全部送到代收点。这个网店管理员叫select。这样我们就可以在家休息了,麻烦的事交给select就好了。当有快递的时候,select负责给我们打电话,期间在家休息睡觉就好了。
但select 代收员比较懒,她记不住快递员的单号,还有快递货物的数量。她只会告诉你快递到了,但是是谁到的,你需要挨个快递员问一遍。
while true {
select(流[]); //阻塞
//有消息抵达
for i in 流[] {
if i has 数据 {
读 或者 其他处理
}
}
}
办法三:epoll
epoll的服务态度要比select好很多,在通知我们的时候,不仅告诉我们有几个快递到了,还分别告诉我们是谁谁谁。我们只需要按照epoll给的答复,来询问快递员取快递即可。
出处:https://www.cnblogs.com/7php/p/14985542.html