工作中需要做一个服务器,要处理成千上万的连接,决定采用ACE的Proactor模型(即Windows下的IOCP)服务器的业务是接受客户端的连接,简单交互后,收到一个数据包,对该数据包进行一些处理后,返回给客户端,断开。数据包的处理可能会比较耗时,包括加解密运算,可能还要查询数据库等用ACE Proactor时,现在有两种选择(方案):
  第一种:从ACE_Service_Handler派生一个类,在这个类中进行网络收发,并进行运算处理(在handle_read_stream中收到后处理)。也就是说所有的工作都在一个线程中完成,整个服务器基本只有这一个线程。
  第二种:从ACE_Service_Handler派生的类中只做网络收发,把收到的数据包放入一个队列,让另一个线程去循环处理,处理后的结果再通过网络发出去。也就是说基本是两个线程,再加一个队列。
  
  第一种做法因为是单线程,基本不需要考虑任何线程同步的问题,实现会比较简单。
  第二种做法可能结构会比较好,但实现上麻烦一些,需要考虑两个线程间的同步,并要在队列的数据包中保存一个连接句柄,用于处理完后的发送,还要考虑数据包处理完后它的所属连接可能已经关闭的问题。  我个人认为ACE的Proactor(即IOCP)本身是异步IO模型,它设计的目的就是为了减少多线程所带来的复杂性,避免CPU线程同步而造成的性能退化。个人认为两个线程一个队列的方法,对于效率的提高没有帮助。
  因此我比较倾向于第一种方案,而有同事则认为应该用第二种方案。  请有相关ACE服务器设计经验的朋友谈谈看法,谢谢。

解决方案 »

  1.   

    这个要看对接卍收到的数据的数据是否会影响网络的性能了。如果每次处理的时间都很短,就没必要增加一个缓冲,还要同步了。如果对数据的处理需要时间的,增加一个或几个线程来处理这个也不错。另外IOCP本身就可以指定超过一个线程来处理IO Request的。
      

  2.   

    一般选择第二种,因为可以避免数据处理占用了I/O处理的时间。──────────────────────
    国内专业的ACE网络编程、开发论坛开通:
    www.acejoy.com 
    www.acedevelop.com
    涉及ACE使用和开发,中间件、服务器端软件的设计,P2P技术,
    socket网络编程、应用开发等内容。
    欢迎加入,大家一起交流、学习成长!
      

  3.   

    应该要用第二种。
    你都说到了,你的数据包处理比较耗时,
    我对完成端口应该开多少工作者线程的理解在你这个例子中就是,
    你处理数据包需要的时间/网络收发的时间=(你要建立的工作者线程数目-1)/主线程数目(就是1)=你要建立的工作者线程数目-1。比如说你的服务器不需要进行任何处理,那么就直接开一个主线程就够了,如果处理数据包时间片基本和处理连接时间相同,只要开两个工作者线程就可以了,这两个线程可以跑同样的线程函数,这样的话,你的服务器可以一直不断的接受连接,两个线程函数轮流值班执行数据包处理,就是说任何时候到来的连接,都可以找到相应的处理线程处理。
    如果你的数据包处理过程明显比较耗时,就应该考虑多开几个,因为你的主线程每接受一个连接的话,可能因为开的线程数不够不能即时找到相应的处理线程,这样,CPU使用效率明显下降。
    注意,上面说的这些都不包括I/O操作,I/O处理时间片是不用考虑的,因为它根本不用你的程序来处理
      

  4.   

    感谢楼上的回复
    好像大多赞成第二种方案啊,第二种方案确实结构比较清晰,网络处理和数据处理分离提出一些不同意见啊我觉得把网络I/O用单独的线程来处理的话(即第二种方案),如果单个数据包处理的时间比较长,就会出现网络I/O很快,CPU处理较慢,即大量的任务会堆积在队列中等待处理。这样总的吞吐量其实是一样的。如楼上所说,IOCP异步模式下,可以认为CPU在网络I/O上是不花时间的,所以服务器CPU的全部时间都花在数据处理运算上。所以我觉得在服务器性能、数据吞吐率等指标上,两种方案应该是一样的,第一种不会比第二种低。楼上acejoy说第二种方案“可以避免数据处理占用了I/O处理的时间”,应该是指单线程中CPU的计算会阻碍对网络I/O的及时响应吧,确实会阻碍,不过我觉得即使不阻碍,CPU也来不及处理不断到来的数据包,CPU的计算能力是一定的。也许有人会说这样可以把数据放在队列中可以缓存起来,弹性更好,可以在瞬间接受大量的连接,但是我觉得这个弹性可以通过ACE_Asynch_Acceptor的open函数的backlog参数(内部是通过多次的AcceptEx来实现的)来解决。两种方法都提供了对连接的缓存,一种是自己把数据先收下来缓存在内存中,另一种是靠操作系统本身提供的机制来缓存。第一种方案的缺点应该在结构上,不便于以后可能把数据计算任务交给另外一台计算机来处理(即分布式的处理)不同意见欢迎讨论
      

  5.   

    >>DentistryDoctor
    另外IOCP本身就可以指定超过一个线程来处理IO Request的。
    -----
    是可以开多个处理线程,最好是cpu个数或者乘以2吧。这可以认为还是第一种方案,因为没有队列,基本不需要线程同步。
      

  6.   

    用第一种还是第二种要看看的是cpu bound还是io bound了
      

  7.   

    有数据库查询的话,肯定要另外开线程做的
    另外,如果数据处理时间太长,会导致网络这块性能低下,看看ace书,上面对数据处理时间和网络消息频率有限制。
      

  8.   

    FT,做过大连接数的绝不会用第一种方案。一个工作线程可能有N种原因阻塞。数据处理线程一般独立开,特别是数据处理时间较长时