使用 BufferedReader.readLine() 读取 inputStream 太慢

Posted

技术标签:

【中文标题】使用 BufferedReader.readLine() 读取 inputStream 太慢【英文标题】:Reading inputStream using BufferedReader.readLine() is too slow 【发布时间】:2011-08-01 11:18:25 【问题描述】:

我正在使用以下代码。

BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line = null;

StringBuilder responseData = new StringBuilder();
while((line = in.readLine()) != null) 
    responseData.append(line);

但读取 200 行需要超过 12 秒。

请帮忙

【问题讨论】:

你有没有想到客户端也可能是慢的?还是网络? 什么是conn?如果您直接阅读 InputStream 会更快(进入您将丢弃的 byte[] 吗? 读取什么?如果问题与缓冲有关,我会感到惊讶。你是通过网络阅读吗?例如,您是否从最后一行没有行终止符的网络连接获取数据,以便 readLine 坐在那里等待它可以识别为行尾的东西?还是来自真正缓慢发送数据的东西? 问题出在while循环中。我测量了时间 你不认为读取过程不能比写入过程快的想法值得考虑吗?您测量了时间 - 当然,但您似乎无法解释您的测量结果。就像我测量了一辆红色汽车的速度,然后坚持认为是红色让它跑得那么快。 【参考方案1】:

我有一个更长的测试要尝试。读取每一行并将其添加到列表中平均需要 160 ns(这可能是您想要的,因为删除换行符不是很有用。

public static void main(String... args) throws IOException 
    final int runs = 5 * 1000 * 1000;

    final ServerSocket ss = new ServerSocket(0);
    new Thread(new Runnable() 
        @Override
        public void run() 
            try 
                Socket serverConn = ss.accept();
                String line = "Hello World!\n";
                BufferedWriter br = new BufferedWriter(new OutputStreamWriter(serverConn.getOutputStream()));
                for (int count = 0; count < runs; count++)
                    br.write(line);
                serverConn.close();
             catch (IOException e) 
                e.printStackTrace();
            
        
    ).start();

    Socket conn = new Socket("localhost", ss.getLocalPort());

    long start = System.nanoTime();
    BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
    String line;

    List<String> responseData = new ArrayList<String>();
    while ((line = in.readLine()) != null) 
        responseData.add(line);
    
    long time = System.nanoTime() - start;
    System.out.println("Average time to read a line was " + time / runs + " ns.");
    conn.close();
    ss.close();

打印

Average time to read a line was 158 ns.

如果您想构建一个 StringBuilder,保留换行符,我建议采用以下方法。

Reader r = new InputStreamReader(conn.getInputStream());
String line;

StringBuilder sb = new StringBuilder();
char[] chars = new char[4*1024];
int len;
while((len = r.read(chars))>=0) 
    sb.append(chars, 0, len);

仍然打印

Average time to read a line was 159 ns.

在这两种情况下,速度都受到发送者而非接收者的限制。通过优化发送器,我将这个时间降低到每行 105 ns。

【讨论】:

使用第二种方法实际上对我来说快一点,谢谢【参考方案2】:

我强烈怀疑这是因为网络连接或您正在与之交谈的网络服务器 - 这不是 BufferedReader 的错。尝试测量这个:

InputStream stream = conn.getInputStream();
byte[] buffer = new byte[1000];
// Start timing
while (stream.read(buffer) > 0)


// End timing

我想您会发现它几乎与解析文本的时间完全相同。

请注意,您还应该为InputStreamReader 提供适当的编码 - 几乎可以肯定,平台默认编码不是您应该使用的。

【讨论】:

亲爱的乔恩,我已经测试了时间。时间仅用于 while 循环 @Shashi:是的,因为那是它实际从网络读取的地方。除非这些行很大,否则这真的不会是 BufferedReader / InputStreamReader 开销。

以上是关于使用 BufferedReader.readLine() 读取 inputStream 太慢的主要内容,如果未能解决你的问题,请参考以下文章

在使用加载数据流步骤的猪中,使用(使用 PigStorage)和不使用它有啥区别?

今目标使用教程 今目标任务使用篇

Qt静态编译时使用OpenSSL有三种方式(不使用,动态使用,静态使用,默认是动态使用)

MySQL db 在按日期排序时使用“使用位置;使用临时;使用文件排序”

使用“使用严格”作为“使用强”的备份

Kettle java脚本组件的使用说明(简单使用升级使用)