BufferedInputStream available() 吃 CPU

Posted

技术标签:

【中文标题】BufferedInputStream available() 吃 CPU【英文标题】:BufferedInputStream available() eating CPU 【发布时间】:2011-11-21 09:02:17 【问题描述】:

我正在从套接字读取消息(通过 TCP 协议),但我注意到 CPU 花费大量时间来调用 BufferedInputStream 的方法 available()。这是我的代码:

    @Override
public void run()


    Socket socket;
    Scanner scanner;
    BufferedInputStream buffer = null;

    try
    
        socket = new Socket(SERVER_HOST, SERVER_PORT);

        System.out.println("Connection Completed");

        InputStream inputStream = socket.getInputStream();
        buffer = new BufferedInputStream(inputStream);

        StringBuilder readCharacter;

        while (true)
        

            readCharacter = new StringBuilder();
            try
            

                while (buffer.available() > 0)
                
                    readCharacter.append((char) buffer.read());
                

            
            catch (IOException e)
            
                e.printStackTrace();
                buffer.close();
            

            String array[] = separe(new String(readCharacter));
         ... //parsing the message

我也尝试使用 int read=buffer.read() 并检查 if (read!=-1) 而不是使用可用函数,但在这种情况下,我无法识别消息的结尾...在我的 StringBuilder 'readCharacter ' 我有不止一条消息,一个接一个..它导致我的解析过程失败......

而不是使用available() 检查,进入readCharacter 我一次只有一条消息......并且解析工作......

你能帮我理解为什么,以及如何避免 CPU 被吃掉吗?

【问题讨论】:

那么,尝试使用 .read() 方法在 while 循环内进行解析。 嗨..你的意思是保持 available() 检查或使用 read()!=-1 ??但是我已经尝试了这两种方法,但它们都不起作用 有一个常见的误解,即您可以通过数据之间的停顿来暗示消息何时开始和结束。您不能发送字节流的消息,只能发送字节。您只能通过阅读内容来确定消息的开始和结束时间。 你能解释一下吗??你说我必须使用另一种机制来处理消息?? 【参考方案1】:

这个循环:

while (buffer.available() > 0)
  
  readCharacter.append((char) buffer.read());
  

可以换成简单的:

readCharacter.append((char) buffer.read());

不要一遍又一遍地调用非阻塞available()(这会消耗大量CPU),只需调用read(),它将阻塞不消耗CPU,直到有东西可用。看起来这是您希望以更少的代码和复杂性实现的目标。

【讨论】:

问题是,如果我删除了while,我读取了一个字符并且我只将一个字符传递给我的解析器.. @marco:现在我看到您的代码通常已损坏(另请参阅 Peter Lawreys 对您的问题的评论)。您不能仅仅因为没有更多字节可以从流中读取就假设您的消息已完成(考虑网络或 I/O 争用)。但是如果你真的想走这条路,先调用阻塞read(),然后调用available()一次,看看你可以在不阻塞的情况下进一步读取多少字节。 如果您阅读42 并且在接下来的 10 秒内没有来自网络的任何内容,这是否意味着这是您的完整输入?或者网络已经饱和,完整的输入是425 123\n?我不知道您实际上在写什么,但您的输入可能是line-token-oriented。也许你的领域被什么东西分开了?也许您预先需要读取一些数据? 是的,我的输入是面向令牌的。在实践中,我发送序列化消息(使用 boost 库的 c++ 文本存档),它们本质上是字符序列......它们用空格分隔,我使用 Java Scanner 解析消息,获取每个字符并将值分配给我的类的字段..【参考方案2】:

available() 本身不吃 CPU。你的循环是什么:

while (buffer.available() > 0) 
    readCharacter.append((char) buffer.read());

虽然字节不可用,但您实际上是多次调用available()(可能是数千次)。由于流的read() 方法被阻塞,您根本不必调用available()。下面的代码做同样的事情,但不占用 CPU。

String line = null;
while ((line = buffer.read()) != null) 
    readCharacter.append(line);

【讨论】:

您的示例无法编译,因为InputStream.read() 的返回类型为int 而不是String。您可能是指BufferedReader.readLine() 方法。 我的意思是BufferedReader。可能变量名buffer 让我很困惑。无论如何,这不是问题。应该在何时何地使用available() 的问题。

以上是关于BufferedInputStream available() 吃 CPU的主要内容,如果未能解决你的问题,请参考以下文章

Java IO BufferedInputStream 和 BufferedOutputStream

BufferedReader 和 BufferedInputStream 的区别

bufferedinputstream的使用

BufferedInputStream 中的读取方法

BufferedInputStream类和BufferedOutputStream类

BufferedInputStream读取流正常,但是BufferedInputStream转化为BufferedReader后 就读取不到数据了?求解