为什么要使用Java的AsynchronousFileChannel?

时间:2010-05-04 05:24:40

标签: java nio

我可以理解为什么网络应用会使用多路复用(不创建太多线程),以及为什么程序会使用异步调用进行流水线操作(效率更高)。但我不明白AsynchronousFileChannel的效率目的。

有什么想法吗?

4 个答案:

答案 0 :(得分:8)

这是一个可用于异步读取文件的通道,即I / O操作是在一个单独的线程上完成的,因此您调用它的线程可以在I / O操作发生时执行其他操作

例如:类的read()方法返回一个Future对象,以获取从文件中读取数据的结果。所以,你可以做的是调用read(),它会立即返回Future个对象。在后台,另一个线程将从文件中读取实际数据。您自己的线程可以继续执行操作,当需要读取数据时,您可以在get()对象上调用Future。然后它将返回数据(如果后台线程尚未完成读取数据,它将使您的线程阻塞,直到数据准备好)。这样做的好处是你的线程不必等待读取操作的整个长度;它可以做其他一些事情,直到它确实需要数据。

请参阅the documentation

请注意,AsynchronousFileChannel将是Java SE 7中的新类,尚未发布。

答案 1 :(得分:3)

我刚刚遇到另一个使用AsynchronousFileChannel的意外原因。在NTFS上对大文件执行随机面向记录的写入(超过物理内存,因此缓存不能帮助所有内容)时,我发现AsynchronousFileChannel在单线程模式下执行的操作数量是普通FileChannel的两倍。

我最好的猜测是,因为异步io归结为Windows 7中重叠的IO,所以NTFS文件系统驱动程序能够在每次调用后不必创建同步点时更快地更新自己的内部结构。

我对RandomAccessFile进行了微基准测试,看看它是如何执行的(结果非常接近FileChannel,而且仍然是AsynchronousFileChannel性能的一半。

不确定多线程写入会发生什么。这是在Java 7上,在SSD上(SSD比磁性快一个数量级,在适合内存的较小文件上快一个数量级)。

看看Linux上是否有相同的比率会很有趣。

答案 2 :(得分:3)

我能想到使用异步IO的主要原因是为了更好地利用处理器。想象一下,你有一些应用程序对文件进行某种处理。而且我们假设您可以以块的形式处理文件中包含的数据。如果您不使用异步IO,那么您的应用程序可能会表现如下:

  1. 读取数据块。此时没有处理器利用率,因为您在等待数据被读取时被阻止。
  2. 处理您刚刚阅读的数据。此时,您的应用程序将在处理数据时开始消耗CPU周期。
  3. 如果要阅读更多数据,请转到#1。
  4. 处理器利用率将上升然后变为零然后上升然后变为零,.......理想情况下,如果您希望应用程序高效并尽可能快地处理数据,您不希望空闲。更好的方法是:

    1. 发出异步读取
    2. 当读取完成后发出下一个异步读取然后处理数据
    3. 第一步是自举。您还没有数据,所以您必须发出一个读数。从那时起,当您收到通知已完成读取时,您将发出另一个异步读取,然后处理数据。这样做的好处是,当您完成处理数据块时,下一次读取可能已完成,因此您始终可以处理数据,因此您可以更有效地使用处理器。如果您的处理在读取完成之前完成,则可能需要发出多个异步读取,以便您有更多数据要处理。

      尼克

答案 3 :(得分:1)

这里没有人提到过:

普通FileChannel(因为它实现InterruptibleChannel)以及使用它的任何内容(例如Files.newOutputStream()返回的OutputStream)都有不幸的 [1] [2] 行为interrupted state中某个帖子中的任何阻止操作(例如read()write())会导致Channel本身关闭java.nio.channels.ClosedByInterruptException

如果这是一个问题,请使用AsynchronousFileChannel替代。