为什么java.nio.FileChannel的transferTo()和transferFrom()更快???它使用DMA吗?

问题描述 投票:0回答:4

为什么 java.nio.FileChannel TransferTo() 和 TransferFrom() 在某些 JVM/OS 组合上比逐字节传输(基于流或使用 ByteBuffer)更快???

这些方法是否使用直接内存访问 (DMA),而不是为每个字节传输发出中断请求 (IRQ)??

jvm nio dma irq filechannel
4个回答
5
投票

这些方法是否使用直接内存访问 (DMA),而不是为每个字节传输发出中断请求 (IRQ)?

具体以实际实施为准,不要求采用任何特定机制。 这在

transferTo
的文档中有所暗示(强调我的):

此方法可能比从此通道读取数据并写入目标通道的简单循环更高效。 许多操作系统可以直接将字节从文件系统缓存传输到目标通道,而无需实际复制它们。

“可能”、“很多”...所以不能保证。

假设使用该方法“可能”更有效(即使只是稍微有效)确实是有道理的,因为您允许 JVM 通过本机代码进行快捷方式(如果使用支持的通道类型)。 他们描述的“简单循环”的工作原理如下: ByteBuffer buf = ByteBuffer.allocateDirect(BUF_SIZE); while ( /* read more condition */ ) { source.read(buf); buf.flip(); target.write(buf); buf.compact(); }

请注意,即使此代码片段使用直接缓冲区,您仍然需要重新使用 Java 进行缓冲区管理(读取、翻转、写入、压缩)。  优化编译器
可能

能够消除其中的一些,但很可能不会。 然而,使用 transferTo

/

transferFrom

 则由 JVM 决定如何传输字节。  如果平台对此类传输具有本机支持,则它可能无需创建中间缓冲区即可实现此目的。  如果没有这样的支持,
JVM 仍然可以实现如上所述的循环
示例

:假设

SocketChannel 被告知直接从 FileChannel

transferFrom
 读取数据。  最近读取了 
FileChannel
,其内容位于操作系统文件缓存中。  
SocketChannel
 可以直接指向操作系统文件缓存并从那里开始传输,而不是读取字节并将其复制到缓冲区中。  至少消除了一轮复制。
现在进一步假设套接字 (A) 实际上连接到其他某个本地进程,例如使用一种称为 
SocketChannel

B 的管道。当 B 开始读取从 A 获取的内容时,它实际上可能直接从再次操作系统文件缓存。 如果 B 只是使用

transferTo

 到另一个频道...你就明白了。

FileChannel API 中有一些解释

0
投票
This method is potentially much more efficient than a simple loop that reads from the source channel and writes to this channel. Many operating systems can transfer bytes directly from the source channel into the filesystem cache without actually copying them.

顺便说一句,transferTo()和transferFrom()都是抽象的,所以这一切都取决于实际的实现
    

它确实使用 DMA/零复制,从而节省了从“From”缓冲区到 CPU 的传输,然后从 CPU 到“to”缓冲区的传输。如需更详细的解释,请阅读 IBM 的

0
投票
文章

在下面的文章中,关于零拷贝

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.