从4秒钟发送5GB数据所引发的对IOCP重叠操作的思索

Squall_zy 2012-12-28 04:45:28
  先澄清一下,标题只是个噱头,所谓发送5GB数据实为重叠投递5GB的发送数据,并非真的发送了5GB数据。写这个帖子只是因为最近看了很多IOCP的文章,我觉得大部分的文章都会误导读者对IOCP的使用。这里我只想表述下我对IOCP的理解。同时希望抛砖引玉,得到更多的信息。
  4秒投递5GB,的确是可以做到的。这意味着你瞬间就安排了发送工作,而眼看着对面的机器花几十分钟的时间来完成对数据的接收。(注意,这几十分钟时间内,发送端应用层并没有做任何send动作)。
  在这种情况下,IOCP的发送可以达到最高的效率,唯有这种方式才是发挥了Overlapped的优势。在这种情况下,发送操作是使用用户Buf直接发的,而不需要通过socket的发送缓冲区。(这是性能的关键)

在这里,我想举个反例,这是我看到的文章中犯的最多的一个错误。看下面的结构体:
typedef struct _PER_IO_CONTEXT
{
OVERLAPPED m_Overlapped;
WSABUF m_wsaBuf;
char m_szBuffer[MAX_BUFFER_LEN]; (这里就是问题!!
OPERATION_TYPE m_OpType;
} PER_IO_CONTEXT;

外部调用接口:
BOOL PostSend( ..., ..., LOVOID pBuf, UINT nSize );

我仅从内存拷贝方面说明上例为何效率不高。
1、还是结合实际应用吧,这样最能说明问题。通常发送TCP数据,要么是定长报文,要么是带头报文。我暂且不说在带头报文长度大于MAX_BUFFER_LEN时,这东西都不能用。假设要发送带头报文,用户首先要开辟一块内存,把报头和身体填充好(这是一次内存拷贝);在调用PostSend函数时,IOCP类会把用户内存拷贝至m_szBuffer变量中作为投递缓存实体(这是第二次内存拷贝);当协议栈处于非SEND_PENDING状态下,WSASend函数会将m_szBuffer的内容拷贝至发送缓冲区(这是第三次内存拷贝);让人惊讶的是,为了发送一个TCP报文,居然消耗了三次内存拷贝的资源和时间。这就是效率低下的根源。
2、还有,你要投递5GB的数据,如果使用如上的结构体,你根本连内存都开不出来。这是因为上面的结构体人为地为每一次发送准备一块内存。假设你要把一个相同的文件同时发给10000个客户端,用上面这个例子会立刻让你服务器瘫痪。
3、真正享受到Overlapped性能的程序,只会使用一次内存拷贝,而不是三次!这需要用户来提供一块发送Buf,并且对该Buf的生存周期负责任;另外,想办法让系统尽量工作于SEND_PENDING状态,免去到发送缓冲区的内存拷贝。
4、最后一个问题是发送缓冲区、接收缓冲区是否该置0的讨论。这个讲起来理论有点多,我只能说各有各的好处。我个人使用不会置0,但如果你对服务器总处于重叠投递状态非常有把握,置0丝毫不会影响性能。但如果你没有把握,那么置0会延后客户端的发送时机(虽然少一次内存拷贝,但滞后了响应时间,所以得不偿失)。
...全文
660 26 打赏 收藏 转发到动态 举报
写回复
用AI写文章
26 条回复
切换为时间正序
请发表友善的回复…
发表回复
WinEggDrop 2013-01-29
  • 打赏
  • 举报
回复
1.如果你的发送缓冲区不设置为0,那么你所有的WSA_Send()投递全要使用系统的非分页内存,每投递1M数据,就占用了1M非分页内存,直至数据传送成功(WSA_Send投递成功完成)。如果你投递了5GB数据,那么5GB非分页内存就全没了,先不说你的系统是否有5GB非分页内存(非分页内存只占物理内存的一部分,不同操作系统最高占用的百分比也不同,VISTA 64位也只能最多占用了40%的总物理内存),非分页内存被耗光的会怎样?轻则有的操作都返回WSAENOBUFS,重则系统网溃,因为所有网络操作及系统驱动都要使用非分页内存。 2.如果你发送缓冲区设置为0,那是根本没怎样用到非分页内存,但你的投递变成阻塞了,就是每个WSA_Send()投递都要数据发送到对方,及对方返回ACK后你的WSA_Send()才算是完成,那估计上面所说的投递5GB数据,发送方也得花和小时,不存在4秒完成。 如果是情况1,那么在现在大内存及64位操作系统下,要达到5GB非分页内存,并非不可能的(如果你有16GB物理内存或以上就没问题了),但是就算实现几秒投递了5GB数据出去,也根本意义不大,因为所有数据还是被锁在系统的内核发送区排成队列等着被发送出去(因为内核发送缓冲区也早就满了)
ithzhang 2013-01-21
  • 打赏
  • 举报
回复
重复利用前面投递好的缓冲区,不过对性能会有影响。不能发挥重叠IO的最大效率。
Squall_zy 2013-01-07
  • 打赏
  • 举报
回复
引用 23 楼 zzz_zou 的回复:
32位系统一下投递5GB。。。。。。。。。。。。。。。。
标题这么写,就是为了突出重叠投递。别说5GB了,10GB照样投。
zzz_zou 2013-01-07
  • 打赏
  • 举报
回复
引用 21 楼 ok1234567 的回复:
我觉得: 内存是内存,指令是指令 “将一块内存发送了1000....遍”只是忙坏了指令,不关内存什么事的 如果能在32位系统下,一下子投递5GB不同的数据,那一定是内存高手! 一般情形下,内存拷贝只是执行效率问题,内存占用则是资源枯竭问题,如果后者无大碍,前者不必太过在意(为了简化控制,只要不是瓶颈)
32位系统一下投递5GB。。。。。。。。。。。。。。。。
ok1234567 2013-01-06
  • 打赏
  • 举报
回复
我觉得: 内存是内存,指令是指令 “将一块内存发送了1000....遍”只是忙坏了指令,不关内存什么事的 如果能在32位系统下,一下子投递5GB不同的数据,那一定是内存高手! 一般情形下,内存拷贝只是执行效率问题,内存占用则是资源枯竭问题,如果后者无大碍,前者不必太过在意(为了简化控制,只要不是瓶颈)
wjb_yd 2013-01-06
  • 打赏
  • 举报
回复
虽不知但觉厉
Squall_zy 2013-01-04
  • 打赏
  • 举报
回复


这是投递完成后的截图。5GB数据。
zzz_zou 2013-01-04
  • 打赏
  • 举报
回复
引用 12 楼 Squall_zy 的回复:
引用 11 楼 zzz_zou 的回复:4秒可以投递5GB的数据吗? 我表示很夸张啊,冒昧问下,投递完后,程序的内存多大? 非页面缓冲池大小多少? 我的测试程序里是将一块内存发送了1000....遍,所以程序本身没有内存占用的问题。IOCP为用户完成发送,但本身使用用户所传递的地址,这也是我主要想讲的一个问题。这个问题我在结论2里已经说明了。 ……
我很好奇,你存不存在问题不是我关心的,你可以把你测试的结果给我说下吗,谢谢啦。
Eleven 2013-01-04
  • 打赏
  • 举报
回复
九州剑王 2013-01-04
  • 打赏
  • 举报
回复
看看各路高人怎么说的
Squall_zy 2013-01-04
  • 打赏
  • 举报
回复
引用 11 楼 zzz_zou 的回复:
4秒可以投递5GB的数据吗? 我表示很夸张啊,冒昧问下,投递完后,程序的内存多大? 非页面缓冲池大小多少?
我的测试程序里是将一块内存发送了1000....遍,所以程序本身没有内存占用的问题。IOCP为用户完成发送,但本身使用用户所传递的地址,这也是我主要想讲的一个问题。这个问题我在结论2里已经说明了。
xhz8000 2013-01-04
  • 打赏
  • 举报
回复
此贴必火!此贴必火!
zzz_zou 2013-01-04
  • 打赏
  • 举报
回复
引用 18 楼 wwwllg 的回复:
你看看虚拟内存大小,如果你真投递出去了,肯定有一个地方保存。 NT,及2003系统,会定时回收内存。 其实我都怀疑,你所谓的投递5GB数据,是如何操作的,贴上你的代码。
如果投递send,当socket缓冲区没有足够空间的时候,会锁定缓冲区,然后返回iopending,当socket有足够空间的时候,应用层的数据被直接丢给tcp协议栈,而不需要拷贝到socket缓冲区。这样看来,他是同一块内存连续投递10000次,那么内存或者虚拟内存应该不会有多少吧
UDX协议 2013-01-04
  • 打赏
  • 举报
回复
你看看虚拟内存大小,如果你真投递出去了,肯定有一个地方保存。 NT,及2003系统,会定时回收内存。 其实我都怀疑,你所谓的投递5GB数据,是如何操作的,贴上你的代码。
这个娜戒海了 2012-12-31
  • 打赏
  • 举报
回复
接分,20分拿来
zzz_zou 2012-12-31
  • 打赏
  • 举报
回复
4秒可以投递5GB的数据吗? 我表示很夸张啊,冒昧问下,投递完后,程序的内存多大? 非页面缓冲池大小多少?
昨夜无风 2012-12-31
  • 打赏
  • 举报
回复
对于大块内存,内存操作机制的确是个影响效率的问题! 但是我不敢苟同楼主说“投递5GB的数据,会给每一次发送都要准备一次内存”,我的想法是既然你有5G的数据,必定有他存在的地方(不管是内存还是硬盘上),我所需要做的就是取得数据的开始地址,然后移动指针去读就可以了。当然要高效率,还得进行内存管理!
UDX协议 2012-12-31
  • 打赏
  • 举报
回复
我的理解,楼主对IOCP,或对内存操作,略懂皮毛。
UDX协议 2012-12-31
  • 打赏
  • 举报
回复
不知道所云,云。。。
Squall_zy 2012-12-30
  • 打赏
  • 举报
回复
写这个帖子,只是因为看了网上太多的代码,觉得很多人被误导了,用a机制的思想去做b机制的事情。有谁敢说iocp和内存拷贝、缓冲区利用没有关系?这不是扯淡么。。。做服务器程序玩的就是内存,你看那些商业封装,人家那么多代码都在干什么?不就是在处理内存,解决效率问题么? 如果你觉得我的技术观点有错误,请指出!这个平台就是让大家去沟通讨论的。 如果不能拿出任何的观点,仅仅是上来喷一下爽快,那是不够负责任的。
加载更多回复(4)

18,358

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧