LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 943|回复: 7

最近研究LumaQQ发现的一个问题

[复制链接]
发表于 2006-11-1 17:47:43 | 显示全部楼层 |阅读模式
LumaQQ接收服务的包是在类Porter里,用了一个循环来轮询所有的IPort,我也写了一个简单的类来测试,不过为什么我在eclipse里运行的时候CPU是100%的利用率(因为死循环),而LumaQQ在运行时却没有占用那么多的CPU呢,是不是在SWT所写的GUI里启动Porter时,Porter线程的Priority会比较低,所以不会占用那么多的CPU呢?请各位赐教。谢了。
发表于 2006-11-2 11:25:49 | 显示全部楼层
循环里面有一段注释解释了这个问题
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-11-2 12:54:44 | 显示全部楼层
Luma 兄,我在Porter的源代码中并没有找到这个注释。是不是我下的源代码的版本太低了?
回复 支持 反对

使用道具 举报

发表于 2006-11-2 14:46:11 | 显示全部楼层
贴出来looklook
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-11-2 23:03:37 | 显示全部楼层
这是Porter的run方法,BTW,您的svn上不去了,我看不到最新的源代码,
[PHP]
/**
         * 不断运转维护所有注册的IPort对象.
         * 通过调用它们的几个函数分别做到清空发送队列/填充接收队列/维护队列的功能.
         * @see IPort#send(ByteBuffer)
         * @see IPort#receive(ByteBuffer)
         * @see IPort#maintain()
         */
        public void run() {
                log.debug("orter已经启动");               
                int n = 0;
            while(!shutdown) {                                        
                // do select
            try {
                n = selector.select(3000);
                // 如果要shutdown,关闭selector退出
                if (shutdown) {
                    selector.close();
                        break;                                
                }
            } catch (IOException e) {
                    log.error(e.getMessage());
                    dispatchErrorToAll(e);
            }
            
            // 处理连接释放请求
            processDisposeQueue();
            
                    // 如果select返回大于0,处理事件
                    if(n > 0) {
                        for (Iterator<SelectionKey> i = selector.selectedKeys().iterator(); i.hasNext();) {
                                        // 得到下一个Key
                                        SelectionKey sk = i.next();
                                        i.remove();
                                        // 检查其是否还有效
                        if(!sk.isValid())
                            continue;

                                        // 处理
                                        INIOHandler handler = (INIOHandler)sk.attachment();
                            try {
                        if(sk.isConnectable())
                            handler.processConnect(sk);
                        else if (sk.isReadable())
                            handler.processRead(sk);
                    } catch (IOException e) {
                            log.error(e.getMessage());
                            handler.processError(e);
                    } catch (PacketParseException e) {
                            log.debug("包解析错误: " + e.getMessage());
                        } catch (RuntimeException e) {
                            log.error(e.getMessage());
                        }
                        }
                        
                        n = 0;
                    }
                    
                    checkNewConnection();                    
                    notifySend();                    
                }
            
        selector = null;
        shutdown = false;
                log.debug("orter已经退出");
        }
[/PHP]
回复 支持 反对

使用道具 举报

发表于 2006-11-2 23:47:31 | 显示全部楼层
notifySend()是单独做的,不像connect和read是检查sk做的,因为一个连接始终是可以send的,如果注册send,就会不断触发send,cpu就100%了
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-11-3 09:52:34 | 显示全部楼层
明白了,多谢Luma兄指点。下面是我的代码:
[PHP]
public void run() {
        SocketAddress remote;
        try {

            remote = new InetSocketAddress(host, defaultPort);

        } catch (Exception ex) {
            System.err.println("Usage: java UDPEchoClientWithChannels host [port]");
            return;
        }

        try {

            channel.configureBlocking(false);

            Selector selector = Selector.open();

            channel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);

            ByteBuffer buffer = ByteBuffer.allocate(4);
            
            int n  = 0;
            while (true) {

                // wait one minute for a connection

                n = selector.select(3000);
                if(n < 1) continue;
                Set readyKeys = selector.selectedKeys();

                if (!readyKeys.isEmpty()) {

                    Iterator iterator = readyKeys.iterator();
                    
                    while (iterator.hasNext()) {

                        SelectionKey key = (SelectionKey) iterator.next();
//                      检查其是否还有效
                        if(!key.isValid())
                            continue;
                        iterator.remove();

                        if (key.isReadable()) {

                            buffer.clear();

                            channel.read(buffer);

                            buffer.flip();

                            int echo = buffer.getInt();

                            System.out.println("Read: " + echo);

                        }

                    }  

                }
                n = 0;
            }

        } catch (IOException ex) {
            System.err.println(ex);
        }

    }
[/PHP]

问题出在[PHP]channel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);[/PHP]这一行,像您说的,我注册了Write操作,所以CPU100%了。把它改成[PHP]channel.register(selector, SelectionKey.OP_READ);[/PHP],CPU就下来了。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-11-3 09:58:12 | 显示全部楼层
我又看了你写的注册那个方法,确实是只注册了Read操作,[PHP]/**
         * 注册一个代理,用在代理验证中
         *
         * @param proxy
         *                 IProxy实现类
         * @throws ClosedChannelException
         *                 如果注册失败
         */
        public void register(IProxy proxy) throws ClosedChannelException {
            SelectableChannel channel = proxy.channel();
            if(channel instanceof SocketChannel)
                    channel.register(selector, SelectionKey.OP_CONNECT, proxy.getNIOHandler());
            else if(channel instanceof DatagramChannel)
                    channel.register(selector, SelectionKey.OP_READ, proxy.getNIOHandler());
            if(!proxies.contains(proxy))
                proxies.add(proxy);
        }[/PHP]比较迷惑的是,我虽然注册了Write操作,但我并没有发包,怎么会触发send,使CPU100%,真是不明白。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表