一、IOCP(I/O Completion Ports)简介

       要实现异步通信,必须要用到一个很风骚的I/O数据结构 ,叫重叠结构“Overlapped”,Windows里所有的异步通信都是基于它的,完成端口也不例外。

      Overlapped重叠结构 这里可以简单的将其理解为一个操作系统和用户之间的参数传递变量,属于“单IO数据”的一部分)

(这张图是个人自己的理解,这两张图结合起来看)

当我们创建一个I/O完成端口的时候,系统内核实际上会创建5个不同的数据结构。

I/O完成端口如何管理线程池

现在是讨论I/O完成端口为什么如此有用的时候了。首先,当我们创建I/O完成端口的时候,需要指定允许多少个线程并发运行(此时并没有创建线程池)。正如前面已经提到过,我们通常会将这个值设为主机的CPU数量。当已完成的I/O项被添加到队列中的时候,I/O完成端口想要唤醒正在等待的线程。但是,完成端口唤醒的线程数量最多不会超过我们指定的数量。因此,如果有4个I/O请求已完成,有4个线程正在等待GetQueuedCompletionStatus,那么I/O完成端口只会唤醒两个线程,而让其他两个线程继续睡眠。当每个线程处理完-一个已完成的I/O项时,会再次调用GetQueuedCompletionStatus. 这时系统发现队列中还有其他的项,于是会唤醒同一个线程来对剩余的项进行处理。

如果读者仔细考虑一 下,就应该注意到有些东西没有太大的意义。如果完成端口只允许同时唤醒指定数量的线程,那么为什么还要让更多的线程在线程池中等待呢?举个例子,假设我们正在一台有两个CPU的机器上运行,我们创建了一个I/O完成端口,并告诉它同时最多只能有两个线程来处理已完成的项。但我们在线程池中创建了4个线程(是CPU数量的两倍)。看起来似乎我们创建了两个多余的线程,它们永远都不会被唤醒来处理任何东西。

但I/O完成端口是非常智能的。当完成端口唤醒一个线程的时候,会将该线程的线程标识符保存在与完成端口相关联的第4个数据结构中,也就是已释放线程列表(released thread list)。这使得完成端口能够记住哪些线程已经被唤醒,并监视它们的执行情况。如果一个已释放的线程调用的任何函数将该线程切换到了等待状态,那么完成端口会检测到这一情况,此时它会更新内部的数据结构,将该线程的线程标识符从已释放线程列表中移除,并将其添加到已暂停线程列表(paused thread list)中(与I/O完成端口相关联的第5个也是最后一个数据结构)。

完成端口的目标是根据在创建完成端口时指定的并发线程的数量,将尽可能多的线程保持在已释放线程列表中。如果一个已释放线程由于任何原因而进入等待状态,那么已释放线程列表会缩减,完成端口就可以释放另一个正在等待的线程。如果一个 已暂停的线程被唤醒,那么它会离开已暂停线程列表并重新进入已释放线程列表。这意味着此时已释放线程列表中的线程数量将大于最大允许的并发线程数量。

让我们把这些总结一下。 假设我们在一 台有两个CPU的机器上运行。我们创建了一个同时最多只允许两个线程被唤醒的完成端口,还创建了4个线程来等待己完成的IO请求。如果3个已完成的IO请求被添加到端的队列中,只有两个线程会被唤醒来对请求进行处理,这降低了可运行线程的数量,并节省了上下文切换的时间。现在,如果一个可运行线程调用了Sleep,WaitForSingleObject,WaitForMultipleObjects,SignalObjectAndWait,一个异步 I/O调用或任何能够导致线程变成不可运行状态的函数, I/O 完成端口会检测到这一情况并立即唤醒第3个线程。完成端口的目标是使CPU保持在满负荷状态下工作。

最后,第一个线程将再次变成可运行状态。当发生这种情况的时候,可运行线程的数量将超过系统中CPU的数量。但是,完成端口仍然知道这一点, 在线程数量降到低于CPU数量之前,它是不会再唤醒任何线程的。I/O完成端口体系结构假定可运行线程的数量只会在很短一段时间内高于最大允许的线程数量,一旦线程进入下一次循环并调用GetQueuedCompletionStatus,可运行线程的数量就会迅速下降。这就解释了为什么线程池中的线程数量应该大于在完成端口中设置的并发线程数量。

IOCP 用来进行线程间通信

I/O完成端口是一项非常棒的技术,并不一定要用于设备I/O还可以用来进行线程间通信。I/O 完成端口有一个函数,名叫PostQueuedCompletionStatus:

IOCP(I/O Completion Port,I/O完成端口)是Windows操作系统中伸缩性最好的一种I/O模型。
    I/O 完成端口是应用程序使用线程池处理异步 I/O 请求的一种机制。处理多个并发异步I/O请求时,使用 I/O 完成端口比在 I/O 请求时创建线程更快更高效。
二、IOCP的优势

    I/O 完成端口可以充分利用 Windows 内核来进行 I/O 调度,相较于传统的 Winsock 模型,IOCP 在机制上有明显的优势。

    相较于传统的Winsock模型,IOCP的优势主要体现在两方面:独特的异步I/O方式和优秀的线程调度机制。

独特的异步I/O方式

    IOCP模型在异步通信方式的基础上,设计了一套能够充分利用Windows内核的I/O通信机制,主要过程为:① socket关联iocp,② 在socket上投递I/O请求,③ 事件完成返回完成通知封包,④ 工作线程在iocp上处理事件。

    IOCP的这种工作模式:程序只需要把事件投递出去,事件交给操作系统完成后,工作线程在完成端口上轮询处理。该模式充分利用了异步模式高速率输入输出的优势,能够有效提高程序的工作效率。

优秀的线程调度机制

    完成端口可以抽象为一个公共消息队列,当用户请求到达时,完成端口把这些请求加入其抽象出的公共消息队列。这一过程与多个工作线程轮询消息队列并从中取出消息加以处理是并发操作。这种方式很好地实现了异步通信和负载均衡,因为它使几个线程“公平地”处理多客户端的I/O,并且线程空闲时会被挂起,不会占用CPU周期。
    IOCP模型充分利用Windows系统内核,可以实现仅用少量的几个线程来处理和多个client之间的所有通信,消除了无谓的线程上下文切换,最大限度的提高了网络通信的性能。

最新文章

  1. 公共交通3D指纹验证系统解决方案
  2. QQ揭秘:如何实现窗体靠边隐藏?【低调赠送:QQ高仿版GG 4.2 最新源码】
  3. dede的安装和配置
  4. Delphi ini文件读写
  5. 通过编程发现Java死锁
  6. 默认选中ComboBox的某一项
  7. JMeter学习(三)元件的作用域与执行顺序
  8. 哈希加密算法 MD5,SHA-1,SHA-2,SHA-256,SHA-512,SHA-3,RIPEMD-160 - aTool
  9. 自定义更新Hibernate Ehcache
  10. dede版权信息修改
  11. 自定义代码块移植,将Xcode中自定义的代码块导出发送到另一台mac
  12. 【 Note 】GDB调试
  13. Terminating app due to uncaught exception 'CALayerInvalid', reason: 'layer <CALayer: 0x7fda42c66e30> is a part of cycle in its layer tree'
  14. 重写comparater比较器
  15. [EXP]K8 jboss invoke deploy getshell exploit
  16. memcached程序端口监控脚本
  17. MVC开发中的常见错误-07-“System.IO.DirectoryNotFoundException”类型的未经处理的异常在 mscorlib.dll 中发生
  18. Javascript-可莱托指数判断
  19. RedHat无法ping通Win10的解决办法
  20. fedora安装字体

热门文章

  1. 【Vulnhub靶场】EMPIRE: BREAKOUT
  2. 利用JavaScript与正则表达式判断输入账号格式是否正确
  3. 负载均衡部署BBS
  4. 字节跳动的一道python面试题
  5. Windows安装软件出现 2502 2503的错误?
  6. Linux中date命令用法
  7. 使用OpenFileDialog打开文件和使用FolderBrowserDialog选定文件夹
  8. 不使用pvc的方式在K8S中部署apisix-gateway
  9. Java中Type接口及其子类
  10. htc 简单的移动效果