Chinaunix

标题: Java 高性能通讯例子 [打印本页]

作者: ludejun98    时间: 2004-12-29 16:17
标题: Java 高性能通讯例子
网络通讯是大家非常常见的问题。
今天我针对项目中遇到的一个实际问题探讨一下高性能通讯模式。

网络通讯中常见到一下情况:线程以循环的方式等待接收信息。

0000>;    while(...){
0000>;        sleep(...);
0000>;        
0000>;        accept(waitTime);
0000>;        ...
0000>;    }

乍看上去这种方式没有什么不妥。其实,这种方式有隐患。
第二行的 sleep周期很难调整。
    如果需要最好的响应速度,就需要设置的很小。但是占用CPU就多;
    如果需要少占CPU,就要设置的大些,可是响应速度(单位时间接收信息量的峰值)会下降。


参考方案如下:
(一)思路:
    1 采用观察者模式替代以前的轮循模式,释放CPU。
    2 由于观察者的update函数是阻塞的,所以在update函数中启动单独的线程处理接收到的单元。
    3 采用一个缓冲队列临时放数据,专门处理数据的线程通过事件驱动模型(Observer模式支持)进行处理。
    4 伪代码如下:


0000>;    // 信息接收部分。
0000>;    while(...){
0000>;        sleep(0);
0000>;        
0000>;        pdu = accept(waitTime);
0000>;            if(pdu!=null){
0000>;               queue.push(pdu);
0000>;            }
0000>;        ...
0000>;    }

解释:
    1 sleep等待的时限为0,就是说,仅仅在必要的时候可以释放CPU调度时间片,
    2 只要CPU不忙,就不会等待。
    3 在 accept 函数中采取的方式是不占用CPU的阻塞等待,当前MFC和Java中都只持。
    4 等待多长时间以后返回,这个时间对其他进程的影响明显缩小。
    5 如果有接收到数据,就放入缓冲区中。

      
2000>;    // 队列,从Observable继承。
2000>;    public final class BQueue extends Observable{
2000>;
2000>;        // 数据放入缓冲区,就自动通知Observer进行处理。
2000>;        public synchronized boolean push(Object ms) {   
2000>;            // 放入缓冲空间。  
2000>;            ....
2000>;            
2000>;            // 这里通知队列的观察者,有数据加入。
2000>;            this.setChanged();
2000>;            this.notifyObservers();                  
2000>;            
2000>;            ....
2000>;        }      
2000>;    }


3000>;    // 队列的观察者,实现Observer接口。
3000>;    public class SendObserver implements Observer{
3000>;        
3000>;        public void update(Observable arg0, Object arg1) {
3000>;               
3000>;                BQueue q = (BQueue)arg0;
3000>;                .....
3000>;                while(q.size()>;0){
3000>;                        pdu = q.pop();
3000>;
3000>;               // 这里对每个PDU,单独启动一个线程进行处理,可以达到响应速度最快
3000>;                        BHandler handler = new BHandler(pdu);
3000>;               handler.startHandle();
3000>;                }               
3000>;        }
3000>;    }

解释:
    1 这里对每个数据的处理采用非阻塞的方式:启动一个线程。
    2 以完成的测试结果:(本机 单位最差机器代表)
      用 LinkedList(链表)做为缓冲队列的数据结构,每秒入队和出队的速度在 亿条量级
      从缓冲队列中取出数据后,并启动线程进行处理,不考虑完成时间,可接收的浪涌:百万条量级。


4000>;    // 可以处理信息单元的线程。
4000>;    public class BHandler implements Runnable{
4000>;
4000>;        // 在构造函数中把PDU保存下来,随后等待线程启动把PDU处理完毕。
4000>;        private RTCS_CTpdu pduForSend;
4000>;        BHandler(RTCS_CTpdu pdu){
4000>;            pduForSend = pdu;
4000>;        }
4000>;            
4000>;        public void run(){
4000>;            // ... 处理
4000>;            .....
4000>;        }
4000>;        
4000>;        public void startHandle(){
4000>;            new Thread(this).start();
4000>;        }
4000>;    }


总结
    1 本文主要针对我们常见的一些通讯缓冲机制进行改良的方案。可能尚有不足之处,欢迎大家探讨指正,个人联系方式:ludj@hisunsray.com 卢先生。
    2 我部分祝鹏先生曾提出动态调整sleep周期的方案,也很可取,探讨请联系:zhupeng@hisunsray.com
作者: solaris10    时间: 2004-12-30 13:35
标题: Java 高性能通讯例子
如果用treemap取代linklist,不知道性能方面是不是会有所提高,
采用缓存机制使性能有了较大提高,但是要注意并发问题。




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2