【发布时间】:2010-05-04 05:24:39
【问题描述】:
我可以理解为什么网络应用会使用多路复用(为了不创建太多线程),以及为什么程序会使用异步调用进行流水线处理(更高效)。但是我不明白 AsynchronousFileChannel 的效率目的。
有什么想法吗?
【问题讨论】:
我可以理解为什么网络应用会使用多路复用(为了不创建太多线程),以及为什么程序会使用异步调用进行流水线处理(更高效)。但是我不明白 AsynchronousFileChannel 的效率目的。
有什么想法吗?
【问题讨论】:
这是一个可用于异步读取文件的通道,即 I/O 操作在单独的线程上完成,因此您调用它的线程可以在 I/O 操作发生时执行其他操作.
例如:类的read()方法返回一个Future对象来获取从文件中读取数据的结果。因此,您可以调用read(),它会立即返回一个Future 对象。在后台,另一个线程将从文件中读取实际数据。你自己的线程可以继续做事,当它需要读取数据时,你在Future对象上调用get()。然后将返回数据(如果后台线程尚未完成读取数据,它将使您的线程阻塞,直到数据准备好)。这样做的好处是您的线程不必等待整个读取操作的长度;在它真正需要数据之前,它可以做一些其他事情。
请注意,AsynchronousFileChannel 将是 Java SE 7 中的一个新类,尚未发布。
【讨论】:
我刚刚遇到了使用 AsynchronousFileChannel 的另一个有点出人意料的原因。在 NTFS 上跨大文件执行面向记录的随机写入(超过物理内存,因此缓存无济于事)时,我发现 AsynchronousFileChannel 在单线程模式下执行的操作是普通 FileChannel 的两倍多。
我最好的猜测是,因为异步 io 归结为 Windows 7 中的重叠 IO,NTFS 文件系统驱动程序能够更快地更新其自己的内部结构,而不必在每次调用后创建同步点。
我对 RandomAccessFile 进行了微基准测试,看看它的性能如何(结果非常接近 FileChannel,仍然是 AsynchronousFileChannel 性能的一半。
不确定多线程写入会发生什么。这是在 Java 7 上的 SSD 上(SSD 比磁性快一个数量级,在适合内存的较小文件上快另一个数量级)。
看看 Linux 上是否有相同的比率会很有趣。
【讨论】:
我能想到使用异步 IO 的主要原因是为了更好地利用处理器。想象一下,您有一些应用程序对文件进行某种处理。还假设您可以分块处理文件中包含的数据。如果您不使用异步 IO,那么您的应用程序可能会表现如下:
处理器利用率将上升,然后到零,然后上升,然后到零,...。理想情况下,如果您希望您的应用程序高效并尽可能快地处理数据,您不希望处于空闲状态。更好的方法是:
第一步是引导。您还没有数据,因此您必须发出读取。从那时起,当您收到读取已完成的通知时,您会发出另一个异步读取,然后处理数据。这样做的好处是,当您完成处理数据块时,下一次读取可能已经完成,因此您始终可以处理数据,从而更有效地使用处理器。如果您的处理在读取完成之前完成,您可能需要发出多个异步读取,以便您有更多数据要处理。
尼克
【讨论】:
这是没有人提到的:
一个普通的FileChannel 实现了InterruptibleChannel 所以它,以及任何使用它的东西,比如Files.newOutputStream() 返回的OutputStream,都有不幸的[1][2]在interrupted state 的线程中对其执行任何阻塞操作(例如read() 和write())的行为将导致Channel 本身以java.nio.channels.ClosedByInterruptException 关闭。
如果这是一个问题,使用AsynchronousFileChannel 是一个可能的替代方案。
【讨论】: