大佬文章:https://blog.csdn.net/piggyxp/article/details/6922277
首先我们应该了解,Windows的俩种通信模型:
1.串行模型:
一个线程等待一个请求,当请求到达时,线程被唤醒对请求进行处理;处理完后再接着等待下一个请求。
缺点:不能同时处理多个请求。
2.并发模型: 一个线程等待一个请求,当请求到达时,线程会创建一个新的线程来处理请求。然后线程进入下一次循环等待下一个请求。新的线程处理完请求后,会自行终止。
缺点:如果请求数量较多,需要创建相对数量的线程,一方面线程频繁地创建、终止会带来开销;另一方面,线程数量过多,但实际上机器的CPU数量有限,且这些线程大多都是处于可调度的状态,那么内核需花费很多在线程的切换上下文的过程,导致没有多少CPU时间来执行真正需要的任务。
为了解决此类问题,可以使用I/O完成端口内核对象。
一、IO完成端口的优点
- 完成端口会充分利用Windows内核来进行I/O的调度,是用于C/S通信模式中性能最好的网络通信模型,没有之一;甚至连和它性能接近的通信模型都没有。
- 首先假设我们使用“串行模型”,也就是“同步”的方式来通信的话,这里说的同步的方式就是说所有的操作都在一个线程内顺序执行完成,这么做缺点是很明显的:因为同步的通信操作会阻塞住来自同一个线程的任何其他操作,只有这个操作完成了之后,后续的操作才可以完成;
一个最明显的例子就是咱们在MFC的界面代码中,直接使用阻塞Socket调用的代码,整个界面都会因此而阻塞住没有响应!所以我们不得不为每一个通信的Socket都要建立一个线程,多麻烦?这不坑爹呢么?所以要写高性能的服务器程序,要求通信一定要是异步的。
那么我们如果要使用 “并发模型” 来解决上面的问题,那么服务器端在每一个客户端连入之后,都要启动一个新的Thread和客户端进行通信,有多少个客户端,就需要启动多少个线程,对吧;但是由于这些线程都是处于运行状态,所以系统不得不在所有可运行的线程之间进行上下文的切换,我们自己是没啥感觉,但是CPU却痛苦不堪了,因为线程切换是相当浪费CPU时间的,如果客户端的连入线程过多,这就会弄得CPU都忙着去切换线程了,根本没有多少时间去执行线程体了,所以效率也会很低。
此时,我们的完成端口就闪亮登场了,它充分利用内核对象的调度,只使用少量的几个线程来处理和客户端的所有通信,消除了无谓的线程上下文切换,最大限度的提高了网络通信的性能。
二、完成端口的相关概念
这里有一篇文章写的太好了&