10

我想写一个套接字。通过阅读有关网络 IO 的信息,在我看来,写入它的最佳方法是执行以下操作:

OutputStream outs=null;
BufferedWriter out=null;
out =
  new BufferedWriter(
    new OutputStreamWriter(new BufferedOutputStream(outs),"UTF-8"));

BufferedWriter会将输入缓冲到推荐的,OutputStreamWriter因为它会阻止编写器为每个字符启动编码器。

然后BufferedOutputStream将缓冲来自 的字节,Writer以避免一次将一个字节潜在地放到网络上。

看起来有点矫枉过正,但这一切似乎都有帮助?感谢任何帮助..

编辑:从 javadoc 上OutputStreamWriter

每次调用 write() 方法都会导致对给定字符调用编码转换器。结果字节在写入底层输出流之前累积在缓冲区中。可以指定此缓冲区的大小,但默认情况下它对于大多数用途来说足够大。请注意,传递给 write() 方法的字符不会被缓冲。

为了获得最高效率,请考虑将 OutputStreamWriter 包装在 BufferedWriter 中,以避免频繁的转换器调用。例如:

Writer out = new BufferedWriter(new OutputStreamWriter(System.out));
4

3 回答 3

10

Buffered* 类的目的是将小的写操作合并成一个更大的写操作,从而减少系统调用的数量,并提高吞吐量。

由于 BufferedWriter 已经在缓冲区中收集写入,然后将缓冲区中的字符转换为另一个缓冲区,并在单个操作中将该缓冲区写入底层 OutputStream,因此已使用大型写入操作调用 OutputStream。因此, BufferedOutputStream 找不到可组合的内容,而且只是多余的。

顺便说一句,这同样适用于 BufferedWriter:只有一次只向写入器传递几个字符时,缓冲才会有所帮助。如果您知道调用者只写入大字符串,那么 BufferedWriter 将找不到任何可组合的内容,而且也是多余的。

于 2013-04-03T22:36:52.580 回答
2

BufferedWriter 会将输入缓冲到 outputStreamWriter,这是推荐的,因为它可以防止编写器为每个字符启动编码器。

由谁推荐,在什么情况下推荐?“启动编码器”是什么意思?无论如何,您是否一次只写一个字符给作者?(我们不太了解您如何使用编写器……这可能很重要。)

然后 BufferedOutputStream 将缓冲来自 Writer 的字节,以避免一次将一个字节潜在地放到网络上。

是什么让您认为它会一次写入一个字节?我认为一次向底层写入器写入一个字节的可能性很小OutputStreamWriter,除非你真的一次写入一个字符。

此外,我希望网络输出流使用类似Nagle 的算法来避免发送单字节数据包。

与优化一样,您应该根据证据进行...您是否在使用和不使用这些缓冲层的情况下进行了任何测试?

编辑:澄清一下,我并不是说缓冲类没有用。在某些情况下,它们绝对是正确的方法。我只是说,与所有优化一样,不应盲目使用它们。您应该考虑您要优化的内容(处理器使用情况、内存使用情况、网络使用情况等)并进行测量。这里有很多因素很重要——尤其是写入模式。如果你已经在写“大块”——写大块的字符数据——那么缓冲区的影响相对较小。如果您实际上一次只写一个字符给作者,那么它们会更重要。

于 2013-04-03T22:17:37.313 回答
2

是的,这是矫枉过正。来自JavadocOutputStreamWriter:“每次调用 write() 方法都会导致在给定字符上调用编码转换器。结果字节在写入底层输出流之前累积在缓冲区中。”。

于 2013-04-04T02:38:44.197 回答