http://cnming.blog.51cto.com/324450/484217完成端口按照如上blog中所写的,CPU的核数4核,线程数8个,因此通过2003可以看到8个CPU,我初始化的工作线程16个,按照看到的8个CPU乘于2。这个完成端口是使用在我自己写的中间件上,反映速度很快,与直接访问数据库对比慢不了多少。没有直接把完成端口捆版在Socket上,因为我研究不透如何很自主地在工作线程中返回数据到Client,因此捆版了一个异步的TCP通讯。
现在还处在测试阶段,用三台笔记本,都写个For循环没有延时访问中间件,CPU负载也很轻。运行没有问题,CPU负载很轻,但是总是使用同一个线程,以下是我PUSH出来的消息内容,其中Index:1代表1号线程在工作,RunningCount(16)代表活动线程有16个,也就是16个线程都处在running状态,或者说IsAlive=true。
若是用我自己的双核笔记本作为中间件服务器,并且Client也运行在我的本机(运行在其它机器没有测试过,防火墙阻挡问题,网路不通,本人不肯开放端口),则4个线程会稍微变化运行,也基本是跑在同一个线程中。Thread RunningCount(16) Index:1 2011-01-24 10:58:04 Client:192.168.2.3:1923 
Thread RunningCount(16) Index:1 2011-01-24 10:58:04 Client:192.168.2.3:1923 
Thread RunningCount(16) Index:1 2011-01-24 10:58:04 Client:192.168.2.3:1923 
Thread RunningCount(16) Index:1 2011-01-24 10:58:04 Client:192.168.2.3:1923 
Thread RunningCount(16) Index:1 2011-01-24 10:58:04 Client:192.168.2.3:1923 
Thread RunningCount(16) Index:1 2011-01-24 10:58:04 Client:192.168.2.3:1923 
Thread RunningCount(16) Index:1 2011-01-24 10:58:04 Client:192.168.2.3:1923 
Thread RunningCount(16) Index:1 2011-01-24 10:58:04 Client:192.168.2.3:1923 
Thread RunningCount(16) Index:1 2011-01-24 10:58:04 Client:192.168.2.3:1923 
Thread RunningCount(16) Index:1 2011-01-24 10:58:04 Client:192.168.2.3:1923 
Thread RunningCount(16) Index:1 2011-01-24 10:58:04 Client:192.168.2.3:1923 
Thread RunningCount(16) Index:1 2011-01-24 10:58:04 Client:192.168.2.3:1923 
Thread RunningCount(16) Index:1 2011-01-24 10:58:04 Client:192.168.2.3:1923 
Thread RunningCount(16) Index:1 2011-01-24 10:58:04 Client:192.168.2.3:1923 
Thread RunningCount(16) Index:1 2011-01-24 10:58:04 Client:192.168.2.3:1923 
Thread RunningCount(16) Index:1 2011-01-24 10:58:03 Client:192.168.2.3:1923 
Thread RunningCount(16) Index:1 2011-01-24 10:58:03 Client:192.168.2.3:1923 感觉应该是在完成端口上等消息的GetQueuedCompletionStatus函数有点小问题,也就是总是同一个线程的GetQueuedCompletionStatus得到了完成端口的消息,难道有优先级等设置?当前我只有一台笔记本在测试,客户的测试人员还没来共同测试。

解决方案 »

  1.   

    呵呵,最近也在搞线程的东西,每次都在一台电脑上开近100个线程跑,但都是跑不一样的。
      Socket通讯比较弱,还是等叫兽来,哈哈
      

  2.   

    TcpLisener的异步操作是封装了IOCP的,你可以试试看是不是仅仅使用同一个线程。不过我想它也不可能啦!因为我们有服务器产品,多会话访问时很自然是多线程的,否则早就趴窝了。
      

  3.   

    没有看你引用的那个帖子,关键是没有看懂这句话“这个完成端口是使用在我自己写的中间件上,反映速度很快,与直接访问数据库对比慢不了多少。没有直接把完成端口捆版在Socket上,因为我研究不透如何很自主地在工作线程中返回数据到Client,因此捆版了一个异步的TCP通讯。”不过我想你用来释放线程的测试有问题。假设按照普通的通讯,在获得第一个访问(Accept)、然后读取和处理数据的时候(即使这个处理根本不是异步的),第二个访问就已经到了,我们可以首先设计出来绝对是并发的测试数据。然后才开始测试。
      

  4.   

    我想本来就应该是一个线程在等待完成端口的消息,假设该线程为A。
    该完成端口对应的所有IO线程向完成端口的队列投递消息后,由A线程来处理。
      

  5.   

    To  sp1234
    首先回答你“没有直接把完成端口捆版在Socket上”这个疑问。
    搜索一下完成端口,基本上是直接捆绑在Socket上的,并不是通过程序调用PostQueuedCompletionStatus来完成消息的投递,例如如下代码:
    #region 把一个套接字绑定在一个端口上的工具方法private static bool DoBind(SafeSocketHandle pListen, SocketAddress pAddress, out byte[] pBuffer, out int pSize)
    {
        FieldInfo mSocketAddress_Buffer = typeof(SocketAddress).GetField("m_Buffer", BindingFlags.Instance | BindingFlags.NonPublic);
        FieldInfo mSocketAddress_Size = typeof(SocketAddress).GetField("m_Size", BindingFlags.Instance | BindingFlags.NonPublic);
        var mBuffer = (byte[])mSocketAddress_Buffer.GetValue(pAddress);
        var m_Size = (int)mSocketAddress_Size.GetValue(pAddress);
        pBuffer = mBuffer;
        pSize = m_Size;    if (Win32Api.bind(pListen, mBuffer, m_Size) != SocketError.Success)
        {
            return false;
        }
        return true;
    }
    #endregion 把一个套接字绑定在一个端口上的工具方法搜索WawaSocket.Net.Iocp就应该能找到范例代码,我好像是在CodeProject下载的
    由于我的中间件有些数据流比较独特,因此我必须能够比较自主发送数据,例如有些数据会发送好几个数据包,但是我没有办法透彻理解完成端口,没有办法修改这个范例中的工作线程的工作模式,因此我选择了不适用绑定模式。而是自己使用一个异步TCP通讯,一个完整的报文接收完毕,再通过PostQueuedCompletionStatus发送消息到完成端口,然后通过自己编写的工作线程去读取消息(GetQueuedCompletionStatus),然后进行工作。
    异步TCP模式、异步TCP+完成端口模式二者的工作效率是有区别的,前者只能应付一个客户端的快速访问,访问代码写在For循环里了,没有任何延时的访问,后者能够应付4台以上的客户端同时使用for循环方式的快速访问(因为测试环境就这么多台电脑了)。每秒钟每客户端大概有80条指令发送并且接收到成功执行之后的返回。---------------------------------------------------------------------
    工作线程是不会释放的,例如服务器有8核心CPU,则工作线程最佳个数是16个,这些资料可以自己搜索。在多客户端同时访问的情况下,必须考虑报文没有一次性接收完毕的情况,也就是对每个客户度的报文的分割问题。因此不能存在前一个还没完成,后一个就已经到了的问题,因此各个客户端的报文必须写在不同的缓冲区。
    服务端接收到客户端的报问,有些报文必须访问好几个服务器,包括有数据库访问、其它单位的中间件访问等等,逻辑上比较复杂。而且有些返回报文也是好几个。WawaSocket.Net.Iocp是一个Echo的完成端口,接收到一两个字节就可以通过完成端口提交了,而我的报文不可以,少说也有几百字节,多到几个MB
      

  6.   

    http://blog.csdn.net/goodmba/archive/2011/02/10/6177475.aspx