我试图了解为什么使用 IOCP。我可以想到两个原因:
- 由于
WSARecv()
不会阻塞,所以我可以处理 1000 个客户端,而不必为每个客户端创建一个新线程(此外,您可以创建的线程数量是有限的,因此您可以处理的客户端数量也会受到限制) . - 既然
WSASend()
不会阻塞,那么当我要发送一个大文件时,我不必创建一个新线程来发送它(如果我没有创建一个新线程那么UI线程当然会阻塞)。
使用 IOCP 还有哪些其他原因?
我试图了解为什么使用 IOCP。我可以想到两个原因:
WSARecv()
不会阻塞,所以我可以处理 1000 个客户端,而不必为每个客户端创建一个新线程(此外,您可以创建的线程数量是有限的,因此您可以处理的客户端数量也会受到限制) .WSASend()
不会阻塞,那么当我要发送一个大文件时,我不必创建一个新线程来发送它(如果我没有创建一个新线程那么UI线程当然会阻塞)。使用 IOCP 还有哪些其他原因?
IOCP 具有您提到的好处,但这并不是 IOCP 独有的。我对本机套接字 API 不太熟悉,但一些 Win32 API 具有“重叠 IO”,它是异步的,但不需要 IOCP。
另一个好处是,使用 IOCP,请求服务线程的数量(在某种程度上)由内核优化。内核知道请求服务线程所做的所有阻塞,它会确保始终有足够多的线程未被阻塞,以便充分利用 CPU。理想情况下,您永远不会阻塞,并且线程数与内核数一样多(假设负载为 100%)。那将是非常有效的。
IOCP 还有助于减少上下文切换,因为不是切换到另一个线程来处理 IO 的结果,而是已经很忙的现有线程GetQueuedCompletionStatus
再次调用。
GetQueuedCompletionStatusEx
可用于减少到内核的转换次数,因为您可以在一次调用中使多个 IO 出列。
此外,它还减少了可避免的批量数据复制和保护环周期。当 recv() 调用请求时,内核不必将数据从网络堆栈缓冲区复制到用户空间缓冲区,用户空间缓冲区由 WSARecv() 提供,然后堆栈可以直接将它们加载到内核空间中。