【问题标题】:Similarities and differences between PipedOutputStream / PipedInputStream (or Reader/Writer) and BlockingQueue for async file writing in Java [closed]PipedOutputStream / PipedInputStream(或Reader/Writer)和BlockingQueue在Java中用于异步文件写入的异同[关闭]
【发布时间】:2012-05-11 14:11:28
【问题描述】:

我正在尝试修改从数据库读取并将结果写入文件的串行程序,这是以阻塞方式完成的,我认为我们可以通过内存缓冲区和文件来提高性能被异步写入“后台”

我可以想到“工作面试”解决方案,使用线程、共享资源、同步块等...... 但我确信有更好的方法(是否有一个不错的小“延迟写入”库可以为我做到这一点?)

java.util.concurrent 软件包是否提供任何帮助? java.nio?或者可能是 JMS/ActiveMQ?

PipedOutputStream / PipedInputStream 作为我的缓冲区的基础怎么样?

如何在 Java 中实现延迟/后台/缓冲/非阻塞/异步文件写入器?

编辑:

根据建议,并避免关闭此问题,(因为我认为根据答案 cmets 和投票仍然相关)这里试图使其更加集中。 (我保留了上面的原始问题,因此答案仍将保留在上下文中,因为有一些非常好的答案)

  • PipedOutputStream/PipedInputStream(或PipedReader/PipedWriter)和BlockingQueue之间的实际区别是什么
  • 是否最好使用后者进行异步文件写入? (或者这是苹果与橙子的比较,如果是,我想知道为什么?)

【问题讨论】:

  • 您的帖子更像是一个讨论主题而不是一个问题,这对于 SO 来说是题外话。尝试您的一些建议,然后发布具体问题。
  • 我对讨论感兴趣,我尊重这对 SO 来说是题外话,但请原谅我再次题外话,这些问题在哪里是题外话?我敢肯定,有很多像我一样的人不需要 SO 来解决特定的编程问题,我会自己弄清楚代码(有人在 99% 的时间之前问过它),但是对于 - “在百万种方法中,什么是最佳实践方式”,这是我正在寻找的真正同行意见,这是programmers.stackexchange.com 代表的意思吗?我应该把我的问题移到那里吗?我想做正确的工作,而不仅仅是做正确的工作
  • 我喜欢这个(有点)问题+1

标签: java multithreading io


【解决方案1】:

您可能希望在生产者(数据库读取器)和消费者(文件写入器)之间使用有界阻塞队列。

Java 的ArrayBlockingQueue 很好地完成了这项工作。如果缓冲区已满,生产者会阻塞,避免任何消耗过多内存的问题。

在并发线程中进行生产和消费最好使用 Java 的 Executors 框架。

【讨论】:

  • 这是我一直在寻找的答案,我将尝试同时使用 BlockingQueue 和 Executors。我实际上将使用用于此答案的 Writer sn-p stackoverflow.com/a/3604974/239168。顺便说一句,那里使用 BlockingDeque 而不是 BlockingQueue 有充分的理由吗?
  • 我没有查看链接,但在标准的生产者消费者场景中,应该不需要队列中的出队。
【解决方案2】:

我可以想到“工作面试”解决方案,使用线程、共享资源、同步块等......但我确信有更好的方法(是否有一个不错的小“延迟写入”库在那里会为我做吗?)

我从未遇到过“延迟写入”库。但我想这实际上只是一个输出流/写入器,它使用一个从队列/缓冲区读取并写入阻塞输出的私有线程写入队列或循环缓冲区。这应该可行,但可能难以避免重复复制数据的成本。

是否有任何 java.util.concurrent 包提供任何帮助?

可能。

java.nio?

可能。

或者也许是 JMS/ActiveMQ?

我怀疑...如果您的目标是写入本地文件。

PipedOutputStream / PipedInputStream 作为我的缓冲区的基础怎么样?

这可能会有所帮助。但是你仍然需要实现读/写流的线程。


忽略实现这一点的机制,我怀疑在这种情况下执行异步 I/O 不会显着加快速度。如果您以当前形式分析应用程序,您可能会发现主要瓶颈是从数据库中获取数据。写入文件可能要快几个数量级。如果是这种情况,那么重叠的数据库和文件 I/O 不太可能显着提高速度。

如果文件输出确实成为瓶颈,那么加速它的更简单方法是增加输出流缓冲区大小。这很简单——只需在BufferedOutputStream 构造函数中添加一个额外的缓冲区大小参数。在进行重大重写之前,您应该尝试一下。

【讨论】:

  • 这是一个非常有用的答案,最好的代码是您意识到不需要编写的代码。我最初认为即使文件 IO 不是瓶颈,如果我不等待它至少会有一些改进,但我同意我需要先分析。我怀疑确实文件 IO 的速度要快几个数量级,这本身就是一个很好的答案,但是您对 BufferedOutputStream 的评论是无价的,另一个“显然,但我怎么没想到”的时刻
  • 讨论其他加快速度的方法,如果您正在读取大量数据集,您应该考虑增加 SQL ResultSets 的提取大小。这可以通过避免数据库通信中的闲聊来极大地提高速度。
  • 谢谢,你的意思是 stmt.setFetchSize(n)?
  • 是的,这行得通,或者您可以在收到结果集时将其设置在结果集上,两者都行。
  • 虽然这个答案对我个人来说是最有用的,但我会尊重投票,事实上@KristofferE 的答案更适合问题的标题,并且会接受他的答案。但这是我在 SO 中得到的最有用的答案之一。
【解决方案3】:

Java 7 在“NIO 2”中有异步 I/O。

如果您不能使用 Java 7,坦率地说,我根本不会费心去尝试实现它。你可以做一些涉及 Futures 的可怕事情,但如果不是负数,那么获得的收益可能为零。

【讨论】:

  • 这是一个很好的观点,会查一下。
猜你喜欢
  • 2023-04-01
  • 1970-01-01
  • 2012-06-02
  • 2017-10-28
  • 2014-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-24
相关资源
最近更新 更多