- 浏览: 2036690 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (651)
- ACE (35)
- BAT (9)
- C/C++ (116)
- fast-cgi (14)
- COM (27)
- python (59)
- CGI (4)
- C# (2)
- VC (84)
- DataBase (29)
- Linux (96)
- P2P (6)
- PHP (15)
- Web (6)
- Memcached (7)
- IME输入法 (11)
- 设计模式 (2)
- 搜索引擎 (1)
- 个人情感 (4)
- 笔试/面试 (3)
- 一亩三分地 (33)
- 历史 (2)
- 地理 (1)
- 人物 (3)
- 经济 (0)
- 不仅仅是笑哦 (43)
- 小故事大道理 (2)
- http://www.bjdsmyysjk120.com/ (0)
- http://www.bjdsmyy120.com/ (0)
- 它山之石可以攻玉 (15)
- 大学生你关注些什么 (28)
- 数据恢复 (1)
最新评论
-
luokaichuang:
这个规范里还是没有让我明白当浏览器上传文件时,STDIN的消息 ...
FastCGI规范 -
effort_fan:
好文章!学习了,谢谢分享!
com技术简介 -
vcell:
有错误os.walk(strPath)返回的已经是全部的文件和 ...
通过python获取目录的大小 -
feifeigd:
feifeigd 写道注意:文章中的CPP示例第二行 #inc ...
ATL入门:利用ATL编写简单的COM组件 -
feifeigd:
注意:文章中的CPP示例第二行 #include " ...
ATL入门:利用ATL编写简单的COM组件
本文主要探讨一下windows平台上的完成端口开发及其与之相关的几个重要的技术概念,这些概念都是与基于IOCP的开发密切相关的,对开发人员来讲,又不得不给予足够重视的几个概念:
1)基于IOCP实现的服务吞吐量
2)IOCP模式下的线程切换
3)基于IOCP实现的消息的乱序问题。
一、IOCP简介
提到IOCP,大家都非常熟悉,其基本的编程模式,我就不在这里展开了。在这里我主要是把IOCP中所提及的概念做一个基本性的总结。IOCP的基本架构图如下:
如图所示:在IOCP中,主要有以下的参与者:
--》完成端口:是一个FIFO队列,操作系统的IO子系统在IO操作完成后,会把相应的IOpacket放入该队列。
--》等待者线程队列:通过调用GetQueuedCompletionStatusAPI,在完成端口上等待取下一个IOpacket。
--》执行者线程组:已经从完成端口上获得IOpacket,在占用CPU进行处理。
除了以上三种类型的参与者。我们还应该注意两个关联关系,即:
--》IOHandle与完成端口相关联:任何期望使用IOCP的方式来处理IO请求的,必须将相应的IOHandle与该完成端口相关联。需要指出的时,这里的IOHandle,可以是File的Handle,或者是Socket的Handle。
--》线程与完成端口相关联:任何调用GetQueuedCompletionStatusAPI的线程,都将与该完成端口相关联。在任何给定的时候,该线程只能与一个完成端口相关联,与最后一次调用的GetQueuedCompletionStatus为准。
二、高并发的服务器(基于socket)实现方法
一般来讲,实现基于socket的服务器,有三种实现的方式(threadperrequest的方式,我就不提了:)):
第一、线程池的方式。使用线程池来对客户端请求进行服务。使用这种方式时,当客户端对服务器的连接是短连接(所谓的短连接,即:客户端对服务器不是长时间连接)时,是可以考虑的。但是,如若客户端对服务器的连接是长连接时,我们需要限制服务器端的最大连接数目为线程池线程的最大数目,而这应用的设计本身来讲,是不好的设计方式,scalability会存在问题。
第二、基于Select的服务器实现。其本质是,使用Select(操作系统提供的API)来监视连接是否可读,可写,或者是否出错。相比于前一种方式,Select允许应用使用一个线程(或者是有限几个线程)来监视连接的可读写性。当有连接可读可写时,应用可以以non-bolock的方式读写socket上的数据。使用Select的方式的缺点是,当Select所监视的连接数目在千的数量级时,性能会打折扣。这是因为操作系统内核需要在内部对这些Socket进行轮询,以检查其可读写性。另一个问题是:应用必须在处理完所有的可读写socket的IO请求之后,才能再次调用Select,进行下一轮的检查,否则会有潜在的问题。这样,造成的结果是,对一些请求的处理会出现饥饿的现象。
一般common的做法是Select结合Leader-Follower设计模式使用。不过不管怎样,Select的本质造成了其在Scalability的问题是不如IOCP,这也是很多high-scalabe的服务器采用IOCP的原因。
第三、IOCP实现高并发的服务器。IOCP是实现high-scalabe的服务器的首选。其特点我们专门在下一小姐陈述。
三、IOCP开发的几个概念
第一、服务器的吞吐量问题。
我们都知道,基于IOCP的开发是异步IO的,也正是这一技术的本质,决定了IOCP所实现的服务器的高吞吐量。
我们举一个及其简化的例子,来说明这一问题。在网络服务器的开发过程中,影响其性能吞吐量的,有很多因素,在这里,我们只是把关注点放在两个方面,即:网络IO速度与DiskIO速度。我们假设:在一个千兆的网络环境下,我们的网络传输速度的极限是大概125M/s,而DiskIO的速度是10M/s。在这样的前提下,慢速的Disk设备会成为我们整个应用的瓶颈。我们假设线程A负责从网络上读取数据,然后将这些数据写入Disk。如果对Disk的写入是同步的,那么线程A在等待写完Disk的过程是不能再从网络上接受数据的,在写入Disk的时间内,我们可以认为这时候Server的吞吐量为0(没有接受新的客户端请求)。对于这样的同步读写Disk,一些的解决方案是通过增加线程数来增加服务器处理的吞吐量,即:当线程A从网络上接受数据后,驱动另外单独的线程来完成读写Disk任务。这样的方案缺点是:需要线程间的合作,需要线程间的切换(这是另一个我们要讨论的问题)。而IOCP的异步IO本质,就是通过操作系统内核的支持,允许线程A以非阻塞的方式向IO子系统投递IO请求,而后马上从网络上读取下一个客户端请求。这样,结果是:在不增加线程数的情况下,IOCP大大增加了服务器的吞吐量。说到这里,听起来感觉很像是DMA。的确,许多软件的实现技术,在本质上,与硬件的实现技术是相通的。另外一个典型的例子是硬件的流水线技术,同样,在软件领域,也有很著名的应用。好像话题扯远了,呵呵:)
第二、线程间的切换问题。
服务器的实现,通过引入IOCP,会大大减少Thread切换带来的额外开销。我们都知道,对于服务器性能的一个重要的评估指标就是:System\ContextSwitches,即单位时间内线程的切换次数。如果在每秒内,线程的切换次数在千的数量级上,这就意味着你的服务器性能值得商榷。ContextSwitches/s应该越小越好。说到这里,我们来重新审视一下IOCP。
完成端口的线程并发量可以在创建该完成端口时指定(即NumberOfConcurrentThreads参数)。该并发量限制了与该完成端口相关联的可运行线程的数目(就是前面我在IOCP简介中提到的执行者线程组的最大数目)。当与该完成端口相关联的可运行线程的总数目达到了该并发量,系统就会阻塞任何与该完成端口相关联的后续线程的执行,直到与该完成端口相关联的可运行线程数目下降到小于该并发量为止。最有效的假想是发生在有完成包在队列中等待,而没有等待被满足,因为此时完成端口达到了其并发量的极限。此时,一个正在运行中的线程调用GetQueuedCompletionStatus时,它就会立刻从队列中取走该完成包。这样就不存在着环境的切换,因为该处于运行中的线程就会连续不断地从队列中取走完成包,而其他的线程就不能运行了。
完成端口的线程并发量的建议值就是你系统CPU的数目。在这里,要区分清楚的是,完成端口的线程并发量与你为完成端口创建的工作者线程数是没有任何关系的,工作者线程数的数目,完全取决于你的整个应用的设计(当然这个不宜过大,否则失去了IOCP的本意:))。
第三、IOCP开发过程中的消息乱序问题。
使用IOCP开发的问题在于它的复杂。我们都知道,在使用TCP时,TCP协议本身保证了消息传递的次序性,这大大降低了上层应用的复杂性。但是当使用IOCP时,问题就不再那么简单。如下例:
三个线程同时从IOCP中读取Msg1,Msg2,与Msg3。由于TCP本身消息传递的有序性,所以,在IOCP队列内,Msg1-Msg2-Msg3保证了有序性。三个线程分别从IOCP中取出Msg1,Msg2与Msg3,然后三个线程都会将各自取到的消息投递到逻辑层处理。在逻辑处理层的实现,我们不应该假定Msg1-Msg2-Msg3顺序,原因其实很简单,在Time1~Time2的时间段内,三个线程被操作系统调度的先后次序是不确定的,所以在到达逻辑处理层,
Msg1,Msg2与Msg3的次序也就是不确定的。所以,逻辑处理层的实现,必须考虑消息乱序的情况,必须考虑多线程环境下的程序实现。
在这里,我把消息乱序的问题单列了出来。其实在IOCP的开发过程中,相比于同步的方式,应该还有其它更多的难题需要解决,这也是与Select方式相比,IOCP的缺点,实现复杂度高。
结束语:
ACE的ProactorFramework,对windows平台的IOCP做了基于Proactor设计模式的,面向对象的封装,这在一定程度上简化了应用开发的难度,是一个很好的异步IO的开发框架,推荐学习使用。
Reference:
MicrosoftTechnet,InsideI/OCompletionPorts
发表评论
-
__declspec(novtable) 的用法
2010-11-27 14:37 1593__declspec(novtable) 的用法 __d ... -
解决URLDownloadToFile缓存问题的两种方法
2010-09-09 15:18 2926解决URLDownloadToFile缓存问题的两种方法 ... -
修改richedit背景
2010-07-19 22:52 1654RichEditCtrl::SetBackgroundCo ... -
使用ADO封装类的数据库程序开发实例(下)
2010-07-12 15:30 1482使用ADO封装类的数据库 ... -
使用ADO封装类的数据库程序开发实例(上)
2010-07-12 15:28 1220使用ADO封装类的数据库 ... -
VC防止窗口和控件闪烁的方法
2010-07-09 21:16 20311、将Invalidate()替换为Invalidate ... -
防止窗口闪烁地办法
2010-07-09 21:13 1519防止窗口闪烁地办法 也许我们都碰到过这种情况,当你 ... -
使用ADO _ConnectionPtr
2010-07-06 16:04 5273// GetUser.cpp : Defines the ... -
VC用ADO访问数据库全攻略
2010-07-06 15:29 1805VC用ADO访问数据库全 ... -
深入GetMessage和PeekMessage (引自-MSDN技术组)
2010-06-10 16:59 3732深入GetMessage和PeekMessage (引自 ... -
界面编程总结(1)
2010-06-02 13:32 4017原文地址:http://blog.csdn.net/byx ... -
获取信息的有关Windows API
2010-05-27 10:01 3155获取信息的有关Windows API 1.窗口信息 ... -
VC中如何实现窗口的隐藏
2010-05-13 10:08 7876VC中如何实现窗口的隐藏 用MFC做的Dialog ... -
SetConsoleCtrlHandler 处理控制台消息
2010-05-07 17:32 18171SetConsoleCtrlHandler 处理控制台消 ... -
解决决错误: error C2850: 'PCH header file'
2010-04-27 19:45 1960解决决错误: error C2850: 'PCH hea ... -
VC++ GDI+编程的字体和文本绘制
2010-04-13 13:12 7990字体是文字显示和打印的外观形式,它包括了文字的字样、风格和尺寸 ... -
VC利用GDI+显示透明的PNG图片
2010-04-12 16:59 115571.在你将要使用GDI+的工程中,完成初始化 ... -
GDI+编程基础(一)GDI+ Vs GDI
2010-04-12 15:59 2342下载源代码一、GDI GDI是位于应用程序与不同硬件之间 ... -
VC画图
2010-04-12 15:50 1548BOOL DrawPic(HDC hdc, TCHAR* ... -
对话框的数据交换--MFC深入浅出
2010-04-12 10:43 2468对话框数据交换指以下两种动作,或者是把内存数据写入对应的控 ...
相关推荐
本文将深入探讨Winsock完成端口模型的工作原理、创建与使用,以及其在实际开发中的优势。 一、Winsock完成端口模型概述 Winsock 完成端口模型是基于异步I/O模型,允许应用程序在发起I/O操作后立即返回,无需等待...
易语言winsock完成端口源码,winsock完成端口,接受连接线程,取错误文本,ServerWorkerThread,socket,WSASocket,WSAAccept,closesocket,Connect,Send,recv,WSARecv,bind,WSAStartup,WSACleanup,htons,inet_ntoa,inet_...
《深入理解Winsock完成端口》 在Windows操作系统中,网络编程往往涉及到大量的并发连接处理,传统的套接字API在高并发环境下效率较低,而Winsock完成端口(IOCP,I/O Completion Port)机制正是为了解决这个问题而...
易语言winsock完成端口.rar 易语言winsock完成端口.rar 易语言winsock完成端口.rar 易语言winsock完成端口.rar 易语言winsock完成端口.rar 易语言winsock完成端口.rar
本压缩包“易语言源码winsock完成端口.rar”包含了易语言编写的一个特定的网络通信模块——Winsock完成端口(IOCP,I/O Completion Port)的源代码。IOCP是Windows操作系统中一种高效的多线程I/O处理机制,尤其适用...
Winsock的完成端口模型借助Widnows的重叠IO和完成端口来实现,完成端口模型懂了之后是比较简单的,但是要想掌握 Winsock完成端口模型,需要对WINDOWS下的线程、线程同步,Winsock API以及WINDOWS IO机制有一定的了解...
完成端口模型(I/O Completion Ports,简称IOCP)是一种高效、多线程的I/O管理机制,尤其适合处理大量并发连接。在Windows系统中,它被广泛应用于网络编程,如服务器应用程序,以提高性能和可扩展性。在这个Delphi...
《易语言实现Winsock完成端口的项目源码解析与应用》 易语言,作为一款中文编程语言,以其直观易懂的语法特性深受初学者和专业开发者喜爱。本项目源码——"winsock完成端口.zip",是针对网络编程中的关键概念——...
Winsock的完成端口模型借助Widnows的重叠IO和完成端口来实现,完成端口模型懂了之后是比较简单的,但是要想掌握Winsock完成端口模型,需要对WINDOWS下的线程、线程同步,Winsock API以及WINDOWS IO机制有一定的了解...
本文将深入探讨如何使用Winsock与完成端口结合,以实现高度并发的网络服务,并介绍一个封装此类模型的类。 完成端口模型的核心在于,它能够有效地管理多个并发的网络连接,通过线程池来处理I/O事件,避免了线程上...
WinSock完成端口IO模型是Windows操作系统中一种高效、多线程的异步I/O处理方式,主要用于网络编程。这个模型充分利用了系统资源,优化了并发处理能力,尤其适合高并发的服务器应用。 首先,我们要了解重叠I/O的概念...
### 一个对Winsock完成端口模型封装的类的研究文档 #### 概述 本文档主要探讨了在Windows环境下如何高效地使用Winsock完成端口模型,并通过C++类的形式对该模型进行了封装,以简化网络服务端程序的开发流程。完成...
Winsock的完成端口模型借助Widnows的重叠IO和完成端口来实现,完成端口模型懂了之后是比较简单的,但是要想掌握Winsock完成端口模型,需要对WINDOWS下的线程、线程同步,Winsock API以及WINDOWS IO机制有一定的了解....
本文将深入探讨如何使用完成端口来开发能够处理大规模响应的Winsock应用程序。 完成端口是Windows内核提供的一个高级I/O模型,它允许将多个异步I/O操作关联到同一个端口,从而实现高效的线程池管理。这种方式特别...
在VB(Visual Basic)编程环境中,使用Winsock控件可以实现对本地或远程计算机的端口扫描功能。Winsock控件是VB中的一个网络通信工具,它提供了TCP/IP协议的基本功能,包括数据发送、接收以及套接字级别的操作。本文...
"Winsock完成端口"是Windows系统中一种高级的I/O模型,主要用于处理大量并发的网络连接。在易语言环境中,这个概念可以帮助开发者构建高效、可扩展的网络应用程序。易语言是一种面向对象的中文编程语言,它提供了...