linux IO多路复用笔记

什么是IO

io是数据的接收和发送操作,linux进程无法直接操作io设备,需要通过系统调用请求内核来完成io操作,内核为每个设备维护一个缓冲区。用户进程发送操作的一个完整io包括两部分:用户空间将数据发送到内核,内核将数据发送到io设备。用户进程接收操作的一个完整io也是包括两部分:内核从io设备中接收数据到缓冲区,从内核缓冲区复制数据到进程空间

5种io模型

阻塞io:进程发起io操作后,进程被阻塞,转到内核空间处理,整个io处理完后返回进程。特点:需要为每一个io请求分配一个进程或线程来处理

非阻塞io:进程发起IO系统调用后,如果内核缓冲区没有数据,需要到IO设备中读取,进程返回一个错误而不会被阻塞;进程发起IO系统调用后,如果内核缓冲区有数据,内核就会把数据返回进程。需要进程主动去轮询。

io多路复用: linuxIO多路复用技术提供一个单进程、单线程监听多个IO读写时间的机制。其基本原理是各个IO将句柄设置为非阻塞IO,然后将各个IO句柄注册到linux提供的IO复用函数上(select,poll或者epoll),如果某个句柄的IO数据就绪,则函数返回通知io ready。调用者进行后续的read write操作。多路复用函数帮我们进行了多个非阻塞IO数据是否就绪的轮询操作,只不过IO多路复用函数的轮询更有效率,因为函数一次性传递文件描述符到内核态,在内核态中进行轮询(epoll则是进行等待边缘事件的触发),不必反复进行用户态和内核态的切换。io多路复用的特点:内核轮询多个io在内核缓冲区是否ready,适合高并发网络服务应用。高并发网络服务应用如果采用阻塞io怎么实现?需要为每个socket连接启动一个线程,频繁的线程切换会导致性能低下。如果采用非阻塞io怎么实现?需要进程轮询每个io,如果有一万个socket连接,确定哪个连接ready需要进行1万次从用户态到内核态的切换,性能低下。

信号驱动io:进程发起io操作,会向内核注册一个信号处理函数,然后进程返回不阻塞,当内核数据就绪时发送一个信号给进程,进程在信号处理函数中调用io函数处理。特点:回调机制,开发难度大

异步io:进程发起一个io操作后,进程返回。内核把整个io处理完后(包括将数据从内核缓冲区复制到用户态)通知进程,进程只需要在指定的数组中引用数据即可

同步io和异步io

同步IO:用户进程发出IO调用,去获取IO设备数据,双方的数据要经过内核缓冲区同步,完全准备好后,再复制返回到用户进程。而复制返回到用户进程会导致请求进程阻塞,直到I/O操作完成。

异步IO:用户进程发出IO调用,去获取IO设备数据,并不需要同步,内核直接复制到进程,整个过程不导致请求进程阻塞。

阻塞io、非阻塞io、io多路复用、信号驱动io都是同步io

同步IO最终需要应用程序调用系统调用从内核来读取数据、异步IO由系统来负责将数据从内核读取到应用程序,应用程序直接使用。

select

1 可以一次性从用户态向内核态传递多个fd

2 内核把当前进程挂到相应io设备的等待队列中

3 内核逐个io判断是否就绪,如果有就绪的就返回(select返回),如果全部未就绪,调用schedule_timeout将进程睡眠

4 当设备驱动发生自身资源可读写后,唤醒其队列上的睡眠进程,进程返回(select返回)

5 如果超过schedule_timeout还没人唤醒,进程唤醒重新遍历fd重复上边流程

优点:

1 一次性传递多个fd

2 在内核中遍历,不必反复进行用户态和内核态的切换

3 具有唤醒机制

缺点:

总结一句话就是:一堆fd从用户态拷贝到内核态,内核态遍历一堆fd,内核态返回后用户态需要遍历一堆fd,这一堆的个数还限制的比较小

1 每次调用select,都需要把fd集合从用户态拷贝到内核态返回时还要从内核态拷贝到用户态,这个开销在fd很多时会很大

2 每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大

3 select返回后,用户不得不自己再遍历一遍fd集合,以找到哪些fd的IO操作可用

4 再次调用select时,fd数组需要重新被初始化

5 select支持的文件描述符数量太小了,内核中采用位图存储,默认是1024

poll

1 通过一个pollfd数组向内核传递需要关注的事件,故没有描述符个数的限制,其他的没有区别

epoll

epoll三大关键要素:mmap、红黑树、链表

mmap:epoll通过mmap将用户空间的一块地址和内核空间的一块地址映射到相同的一块物理内存地址,减少用户态和内核态之间的数据交换,内核可以直接看到监听的句柄

红黑树:epoll采用红黑树来存储监听的套接字。epoll_ctl添加或者删除一个套接字时,都在红黑树上处理,红黑树的插入和删除性能比较好

双向链表:epoll的rdllist采用的就是双向链表

epoll主要函数

1 int  epoll_create (int size );

采用epoll_create()建立epoll描述符来记录需要监控的fd(select每次都把fd集合从用户空间赋值到内核空间)

在epoll早期的实现中,对于监控文件描述符的组织并不是使用红黑树,而是hash表。这里的size实际上已经没有意义。

2 int  epoll_ctl (int epfd,int op,int fd,struct epoll_event *event);

epoll_ctrl用来添加或删除待监控的fd。当调用epoll_ctrl添加fd和事件时,该事件都会和相应的设备驱动程序建立回调关系,当相应的事件发生后,调用ep_poll_callback回调函数,这个函数把这个事件添加到rdllist双向链表中。

op可以指定操作类型:EPOLL_CTL_ADD(往事件表中注册fd上的事件)、EPOLL_CTL_MOD(修改fd上的注册事件)、EPOLL_CTL_DEL(删除fd上的注册事件)

 event:指定fd关注的事件

3 int epoll_wait (int epfd,struct epoll_event* events,int maxevents,int timeout );

(1) epoll_wait调用ep_poll,当rdllist为空(无就绪fd)时挂起当前进程,直到rdlist不空时进程才被唤醒。

(2) 文件fd状态改变,导致相应fd上的回调函数ep_poll_callback()被调用。

(3) ep_poll_callback将相应fd对应epitem加入rdlist,导致rdlist不空,进程被唤醒,epoll_wait得以继续执行。

(4) ep_events_transfer函数将rdlist中的epitem拷贝到txlist中,并将rdlist清空。

(5) ep_send_events函数,它扫描txlist中的每个epitem,调用其关联fd对用的poll方法。此时对poll的调用仅仅是取得fd上较新的events(防止之前events被更新),之后将取得的events和相应的fd发送到用户空间(封装在struct epoll_event,从epoll_wait返回)。

ET模式和LT模式

epoll_wait返回的两个时机:

时机一:fd状态改变,ep_poll_callback被调用,加入rdllist。对于读操作:一是buffer由不可读状态变为可读的时候。二是有新数据到达,buffer中待读的内容变多的时候。对于写操作:一是buffer由不可写变为可写的时候。二是旧数据发送走,buffer中可写的空间变大的时候。

时机二:fd的events中有相应的事件位置1时。对于读操作:buffer中有数据可读,buffer不为空的时候fd的events的可读位就置1。对于写操作:buffer中有空间可写,buffer不满的时候fd的可写位就置1。

对于ET模式,只采用上述时机一。LT模式采用上述时机一和时机二。


ET模式注意事项

ET模式下,读操作如果一次没有读尽buffer中的数据,将得不到读就绪的通知,造成buffer中已有的数据无机会读出,除非有新的数据再次到达。因此ET模式下需要注意:1,采用非阻塞io  2,循环读写,保证读完、写满。

ET模式和LT模式如何保证数据可以被读完?ET模式由用户程序来循环,LT模式通过多次epoll_wait返回来循环。

建议采用ET模式+非阻塞io+循环读写,相比LT模式,省去了多次epoll_wait的调用。

https://blog.csdn.net/daaikuaichuan/article/details/88777274

高并发服务器模型epoll+线程池


这种架构特点如下:

1 基于I/O多路复用的思想,通过单线程I/O多路复用,可以达到高效并发,同时避免了多线程I/O来回切换的各种开销。

2 由于业务多跟数据库打交道会造成阻塞,基于线程池的多工作者线程,可以充分发挥和利用多线程的优势。

创建一个epoll实例;

while(server running)

{

    epoll等待事件;

    if(新连接到达且是有效连接)

    {

        accept此连接;

        将此连接设置为non-blocking;

        为此连接设置event(EPOLLIN | EPOLLET ...);

        将此连接加入epoll监听队列;

        从线程池取一个空闲工作者线程并处理此连接;

    }

    else if(读请求)

    {

        从线程池取一个空闲工作者线程并处理读请求;

    }

    else if(写请求)

    {

        从线程池取一个空闲工作者线程并处理写请求;

    }

    else

        其他事件;     

}

golang net库网络实现分析

golang中的网络io全部是非阻塞io

网络io的read操作如下:

1 golang协程通过系统调用来读取数据

2 如果数据没准备好,调用waitRead----->runtime_pollWait----->poll_runtime_pollWait------>netpollblock------>gopark------->park_m--------->schedule  进行协程的切换。这样就通过非阻塞io加协程切换模拟出了阻塞io,可以采用阻塞io的简单开发方式

3 golang中起一个线程定期执行sysmon函数,sysmon---->netpoll----->epollwait  返回ready的协程列表,sysmon----->injectglist------>casgstatus将ready的协程的状态设置为可运行

4 读io的协程继续运行,再次通过系统调用来读取数据,最终返回

底层本质是:非阻塞io+epoll+线程池+任务队列的模型,epoll返回哪个任务的io 已经ready,线程池中的线程取io ready的任务继续执行,goalng通过协程将这些全部封装好了,通过协程实现了非阻塞的io可以采用阻塞的方式编程

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

推荐阅读更多精彩内容