• 网络IO模型


    同步(synchronous) IO、异步(asynchronous) IO、阻塞(blocking) IO、非阻塞(non-blocking)IO

    1、阻塞IO(blocking IO)

    系统调用(一般是IO接口)不返回调用结果并让当前线程一直阻塞,只有当该系统调用获得结果或者超时出错时才返回。

    在此期间,线程将无法执行任何运算或响应任何的网络请求。

    一个简单的改进方案是在服务器端使用多线程(或多进程)。多线程(或多进程)的目的是让每个连接都拥有独立的线程(或进程),这样任何一个连接的阻塞都不会影响其他的连接。

    传统意义上,进程的开销要远远大于线程,所以如果需要同时为较多的客户机提供服务,则不推荐使用多进程;

    如果单个服务执行体需要消耗较多的CPU资源,譬如需要进行大规模或长时间的数据运算或文件访问,则进程较为安全。

    2、非阻塞IO(non-blocking IO)

    当用户进程发出read操作时,如果kernel中的数据还没有准备好,那么它并不会block用户进程,而是立刻返回一个error。

    从用户进程角度讲 ,它发起一个read操作后,并不需要等待,而是马上就得到了一个结果。用户进程判断结果是一个error时,它就知道数据还没有准备好,于是它可以再次发送read操作。

    一旦kernel中的数据准备好了,并且又再次收到了用户进程的system call,那么它马上就将数据拷贝到了用户内存,然后返回。

    在非阻塞式IO中,用户进程需要不断的主动询问kernel数据准备好了没有,严重影响性能。

    3、多路复用IO(IO multiplexing)

    即 select/epoll

    select/epoll的好处就在于单个process就可以同时处理多个网络连接的IO。

    它的基本原理就是select/epoll这个function会不断的轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程。

    当用户进程调用了select,那么整个进程会被block,而同时,kernel会“监视”所有select负责的socket,当任何一个socket中的数据准备好了,select就会返回。这个时候用户进程再调用read操作,将数据从kernel拷贝到用户进程。

    事件驱动模型:  

      普通的非阻塞IO是各个IO自行盲询自己的IO是否就绪,而IO复用则是以一个系统调用来完成所有IO是否就绪的轮询,如果就绪则执行IO操作。

      事件驱动是IO复用的一种升级版本,IO复用是轮询所有的IO。

      而事件驱动是只处理已经就绪的IO,首先开启socket信号驱动的功能(将socket放到epoll文件系统里file对象对应的红黑树,并在内核终端处理程序中注册回调函数),当网卡检测到某个socket有数据来到时,内核就会将socket放入IO就绪队列,并从网卡拷贝数据到内核。

      IO复用的缺点

        单线程能轮询的文件描述符有限1024;

        需要轮询所有的IO,如果当前IO事件很多,但是就绪的非常少,那么会导致效率下降;

      事件驱动则可以解决上述两个缺点,没有文件描述符的限制(通常都非常大,比如2G内存的机器都有655350);只处理已经就绪的IO,可以过滤掉不活跃的IO轮询带来的损失。

      同时使用mmap(内存映射)的方式,来减少IO数据从内核-用户控件的拷贝。

        MMAP介绍:

          1、用户空间、内核空间都是不能直接访问设备的物理地址

          2、内核空间如果要访问设备的物理地址,需要先映射物理地址到内核的虚拟地址(页缓存)上,以后驱动程序访问这个虚拟地址

          3、用户空间只能通过系统调用访问映射好的内核虚拟地址(页缓存)

          这上面会有2次数据拷贝,硬件和内核空间,用户空间和内核空间。

        而MMAP的目的是将2次拷贝转换为1次拷贝,节约拷贝数据带来的消耗。

        将物理地址映射到一块内存,应用程序(用户区域)可以直接访问这块内存。

      事件驱动的缺点:

        如果各个IO都比较活跃,那么IO复用的全轮询也不会有太多的性能损失,但是注册socket驱动事件却会带来一些负担。

     4、异步IO(Asynchronous I/O)

     用户进程发起read操作之后,立刻就可以开始去做其它的事。

    而另一方面,从kernel的角度,当它受到一个asynchronous read之后,首先它会立刻返回,所以不会对用户进程产生任何block。然后,kernel会等待数据准备完成,然后将数据拷贝到用户内存,当这一切都完成之后,kernel会给用户进程发送一个signal,告诉它read操作完成了。

    转自:http://blog.chinaunix.net/uid-28458801-id-4464639.html ,https://www.cnblogs.com/souyoulang/p/8873558.html

  • 相关阅读:
    PayPal(贝宝)支付接口、文档、IPN
    C# LiveUpdate.exe实现文件在线更新升级
    C# 邮件发送
    VisualStudio11预览
    zen coding for visual studio 2010(vs2010)
    淘宝API开发系列淘宝API相关了解
    多年积累
    专业淘友必不可少的资料,教你如何玩转淘宝!
    极速理解设计模式系列
    ASP.NET开发人员经常使用的三十三种代码
  • 原文地址:https://www.cnblogs.com/lqyy/p/11032488.html
Copyright © 2020-2023  润新知