在本文中,我们将带你了解为什么Java中的FileChannel不是非阻塞的?在这篇文章中,我们将为您详细介绍为什么Java中的FileChannel不是非阻塞的?的方方面面,并解答javafilec
在本文中,我们将带你了解为什么Java中的FileChannel不是非阻塞的?在这篇文章中,我们将为您详细介绍为什么Java中的FileChannel不是非阻塞的?的方方面面,并解答java filechannel原理常见的疑惑,同时我们还将给您一些技巧,以帮助您实现更有效的08. Java NIO FileChannel 文件通道、8,Java NIO FileChannel、Apache的Flume和FileChannel有什么用、Golang Channels 的阻塞和非阻塞机制解析。
本文目录一览:- 为什么Java中的FileChannel不是非阻塞的?(java filechannel原理)
- 08. Java NIO FileChannel 文件通道
- 8,Java NIO FileChannel
- Apache的Flume和FileChannel有什么用
- Golang Channels 的阻塞和非阻塞机制解析
为什么Java中的FileChannel不是非阻塞的?(java filechannel原理)
我想编写一个可以同时写入多个文件的程序。认为可以通过使用非阻塞模式在一个线程中实现。但是FileChannel不支持非阻塞模式。有人知道为什么吗?
答案1
小编典典UNIX不支持非阻塞的文件I / O,看到非阻塞I /
O与常规文件。由于Java应该(至少尝试在所有平台上)提供相同的行为,因此FileChannel
不会实现SelectableChannel
。
但是,Java
7将包括一个AsynchronousFileChannel
支持
异步 文件I / O 的新类,这是与非阻塞I / O不同的机制。
通常,只有套接字和管道才能真正通过select()
机制支持非阻塞I / O。
08. Java NIO FileChannel 文件通道
Java NIO中的FileChannel是用于连接文件的通道。通过文件通道可以读、写文件的数据。Java NIO的FileChannel是相对标准Java IO API的可选接口。
FileChannel不可以设置为非阻塞模式,他只能在阻塞模式下运行。
打开文件通道(Opening a FileChannel)
在使用FileChannel前必须打开通道,打开一个文件通道需要通过输入/输出流或者RandomAccessFile,下面是通过RandomAccessFile打开文件通道的案例:
RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");
FileChannel inChannel = aFile.getChannel();
从文件通道内读取数据(Reading Data from a FileChannel)
读取文件通道的数据可以通过read方法:
ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = inChannel.read(buf);
首先开辟一个Buffer,从通道中读取的数据会写入Buffer内。接着就可以调用read方法,read的返回值代表有多少字节被写入了Buffer,返回-1则表示已经读取到文件结尾了。
向文件通道写入数据(Writing Data to a FileChannel)
写数据用write方法,入参是Buffer:
String newData = "New String to write to file..." + System.currentTimeMillis();
ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
buf.put(newData.getBytes());
buf.flip();
while(buf.hasRemaining()) {
channel.write(buf);
}
注意这里的write调用写在了wihle循环汇总,这是因为write不能保证有多少数据真实被写入,因此需要循环写入直到没有更多数据。
关闭通道(Closing a FileChannel)
操作完毕后,需要把通道关闭:
channel.close();
FileChannel Position
当操作FileChannel的时候读和写都是基于特定起始位置的(position),获取当前的位置可以用FileChannel的position()方法,设置当前位置可以用带参数的position(long pos)方法。
long pos channel.position();
channel.position(pos +123);
假设我们把当前位置设置为文件结尾之后,那么当我们视图从通道中读取数据时就会发现返回值是-1,表示已经到达文件结尾了。 如果把当前位置设置为文件结尾之后,在想通道中写入数据,文件会自动扩展以便写入数据,但是这样会导致文件中出现类似空洞,即文件的一些位置是没有数据的。
FileChannel Size
size()方法可以返回FileChannel对应的文件的文件大小:
long fileSize = channel.size();
FileChannel Truncate
利用truncate方法可以截取指定长度的文件:
channel.truncate(1024);
FileChannel Force
force方法会把所有未写磁盘的数据都强制写入磁盘。这是因为在操作系统中出于性能考虑回把数据放入缓冲区,所以不能保证数据在调用write写入文件通道后就及时写到磁盘上了,除非手动调用force方法。 force方法需要一个布尔参数,代表是否把meta data也一并强制写入。
channel.force(true);
8,Java NIO FileChannel
A Java NIO FileChannel is a channel that is connected to a file. Using a file channel you can read data from a file, and write data to a file. The Java NIO FileChannel class is NIO''s an alternative to reading files with the standard Java IO API.
A FileChannel
cannot be set into non-blocking mode. It always runs in blocking mode.
Opening a FileChannel
Before you can use a FileChannel
you must open it. You cannot open a FileChannel directly. You need to obtain a FileChannel via an InputStream, OutputStream, or a RandomAccessFile. Here is how you open a FileChannel via a RandomAccessFile:
RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");
FileChannel inChannel = aFile.getChannel();
Reading Data from a FileChannel
To read data from a FileChannel
you call one of the read()
methods. Here is an example:
ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = inChannel.read(buf);
First a Buffer
is allocated. The data read from the FileChannel
is read into the Buffer
.
Second the FileChannel.read()
method is called. This method reads data from the FileChannel
into theBuffer
. The int
returned by the read()
method tells how many bytes were witten into the Buffer
. If -1 is returned, the end-of-file is reached.
Writing Data to a FileChannel
Writing data to a FileChannel
is done using the FileChannel.write()
method, which takes a Buffer
as parameter. Here is an example:
String newData = "New String to write to file..." + System.currentTimeMillis();
ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
buf.put(newData.getBytes());
buf.flip();
while(buf.hasRemaining()) { channel.write(buf);}
Notice how the FileChannel.write()
method is called inside a while-loop.
There is no guarantee of how many bytes the write()
method writes to the FileChannel.
Therefore we repeat the write()
call until the Buffer
has no further bytes to write.
Closing a FileChannel
When you are done using a FileChannel
you must close it. Here is how that is done:
channel.close();
FileChannel Position
When reading or writing to a FileChannel
you do so at a specific position. You can obtain the current position of theFileChannel
object by calling the position()
method.
You can also set the position of the FileChannel
by calling the position(long pos)
method.
Here are two examples:
long pos channel.position();
channel.position(pos +123);
If you set the position after the end of the file, and try to read from the channel, you will get -1 , the end-of-file marker.
If you set the position after the end of the file, and write to the channel, the file will be expanded to fit the position and written data. This may result in a "file hole", where the physical file on the disk has gaps in the written data.
FileChannel Size
The size()
method of the FileChannel
object returns the file size of the file the channel is connected to. Here is a simple example:
long fileSize = channel.size();
FileChannel Truncate
You can truncate a file by calling the FileChannel.truncate()
method. When you truncate a file, you cut it off at a given length. Here is an example:
channel.truncate(1024);
This example truncates the file at 1024 bytes in length.
FileChannel Force
The FileChannel.force()
method flushes all unwritten data from the channel to the disk. An operating system may cache data in memory for performance reasons, so you are not guaranteed that data written to the channel is actually written to disk, until you call the force()
method.
The force()
method takes a boolean as parameter, telling whether the file meta data (permission etc.) should be flushed too.
Here is an example which flushes both data and meta data:
channel.force(true);
Apache的Flume和FileChannel有什么用
这篇文章主要介绍“Apache的Flume和FileChannel有什么用”,在日常操作中,相信很多人在Apache的Flume和FileChannel有什么用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Apache的Flume和FileChannel有什么用”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
Flume使用简单可扩展的数据模型,支持在线分析应用程序。
FileChannel是支持并行加密写入多个磁盘的持久化Flume channel.
概述
当使用Flume 时,每个工作流都拥有Source, Channel, and Sink,典型例子是一个webserver通过RPC将事件(events)写入Source(例如:Avro Source),sources又将events写入MemoryChannel,同时HDFS Sink从MemoryChannel消费events,并写入HDFS
MemoryChannel提供高吞吐的性能,同时在断电和程序崩溃之后会造成数据丢失。因此需要开发一个持久化的Channel。File Channel的目标是提供一个可靠的高吞吐Channel。File Channel保证当事务被提交后,不会因为一系列程序崩溃或者掉电而造成数据丢失。
值得注意的是,FileChannel本身不会对数据进行任何复制。 因此,它只能与底层磁盘一样可靠。 由于其耐用性而使用FileChannel的用户在购买和配置硬件时应考虑到这一点。 底层磁盘应为RAID,SAN或类似磁盘。
许多系统以少量数据丢失风险换取更高的吞吐量(例如fsync,每隔几秒从内存到磁盘)。 Flume团队决定采用不同的方法实现FileChannel。 Flume是一个事务性系统,多个事件(events)可以是单个事务中实现或者put或者take的操作。 批量大小可用于控制吞吐量。 使用大的批处理容量,Flume可以通过流处理数据,在高吞吐量的情况下而不会丢失数据。 批量处理的大小完全可以由客户端控制。 这对于RDBMS用户比较熟悉。
Flume事务或者包含Puts 操作,或者Takes操作,不同时支持两个操作,同时commit和rollback 也是如此。每个事物transanction都是了Put 和Take方法。Source 调用Put 方法将事件写入Channel,Sinks执行Takes 方法从channel中取数据。
设计
FileChannel除了基于内存队列之外,还基于预写日志WAL。每个事务都根据事务类型(Take或Put)写入WAL,并相应地修改队列。每次提交事务时,都会在相应的文件上调用fsync,以确保数据确实写入磁盘上,并将指向该事件的指针放在队列中。该队列就像任何其他队列一样:它管理尚未被Sink消费的内容。在获取期间,将队列中指针删除。然后直接从WAL读取事件。由于目前可用的RAM量很大,因此从操作系统文件缓存中进行读取非常常见。
程序崩溃后,可以重放WAL以将队列置于崩溃之前的状态,因此已提交的事务不会丢失。重放WAL可能非常耗时,因此队列本身会定期写入磁盘。将队列写入磁盘称为检查点。崩溃后,队列从磁盘加载,然后只有队列保存到磁盘后才提交事务,这大大减少了必须读取的WAL数量。
例如,channel中有两个如下图所示的events。
WAL包含三个重要项:事务ID,序列号和事件数据。 每个事务都有一个唯一的事务ID,每个事件都有一个唯一的序列号。 事务id仅用于将事件分组到事务中,而在重放日志时使用序列号。 在上面的示例中,事务id为1,序列号为1,2和3。
当队列保存到磁盘(检查点)时,序列号也会增加并保存。 在重新启动时,首先加载来自磁盘的队列,然后重放序列号大于队列的所有WAL条目。 在检查点操作期间,通道被锁定,因此任何Put或Take操作都不能改变它的状态。 允许在检查点期间修改队列将导致存储在磁盘上的队列的快照不一致。
在上面的示例队列中,在提交事务1之后发生检查点,导致队列中的事件a,事件b被保存到磁盘,同时序列号为4。
然后,事件a在事务2中被taken。
如果发生崩溃,则从磁盘读取队列检查点。 请注意,由于检查点发生在事务2之前,因此队列中当前存在事件a和b。 然后读取WAL并应用序列号大于4的任何已提交事务,从而导致从队列中删除“a”(该操作的event是[2,5,Take "a"])。
上述设计不包括两个项目。 在检查点发生时正在进行的Takes和Puts将丢失。 假设在获取“a”之后发生了检查点:
如果此时发生崩溃,则在上述设计下,事件“b”将在队列上并且在重放时将重放序列号大于5的任何WAL条目。 将重播事务2的回滚[2,6,Rollback],但不会重放事务2的Taken[2,4,Take "a"]。 因此,“a”不会被放置在队列中,从而导致数据丢失。 Puts也会采用类似的方案。 因此,当发生队列检查点时,也会写出仍在进行中的事务,以便可以适当地解决上述场景。
实现
FileChannel存储在Flume项目的flume-file-channel模块中,包名是org.apache.flume.channel.file。 上面描述的队列的名称为FlumeEventQueue,WAL名称为Log。 队列本身是一个循环数组,由内存映射文件支持,而WAL是一组使用LogFile类及其子类编写和读取的文件。
到此,关于“Apache的Flume和FileChannel有什么用”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注小编网站,小编会继续努力为大家带来更多实用的文章!
Golang Channels 的阻塞和非阻塞机制解析
Golang Channels 的阻塞和非阻塞机制解析
引言:
Channels 是 Golang 中重要的并发通信机制之一,它允许不同的 Goroutines 之间进行通信和同步。在使用 Channels 的时候,我们经常会遇到阻塞和非阻塞的情况。本文将介绍 Channels 的阻塞和非阻塞机制,并通过代码示例来阐述其原理和使用方法。
- 阻塞和非阻塞的基本概念
在并发编程中,阻塞和非阻塞是两种常见的处理方式。简单来说,阻塞是指当一个 Goroutine 试图读取或写入一个 Channel 时,如果 Channel 没有准备好,那么该 Goroutine 会被阻塞,直到 Channel 准备好;非阻塞则是指 Goroutine 在无论 Channel 是否准备好的情况下立即继续执行。
在 Golang 中,我们可以通过以下两种方式来实现阻塞和非阻塞的机制:利用 Channel 的长度和使用 select 语句。下面我们将一一介绍。
- 利用 Channel 的长度实现阻塞和非阻塞
对于无缓冲的 Channel,其长度为0。当一个 Goroutine 试图往一个无缓冲 Channel 中写入数据时,如果没有其他 Goroutine 在相同 Channel 上等待读取,写入操作会被阻塞,直到有 Goroutine 准备好读取数据。同样地,当一个 Goroutine 试图从一个无缓冲 Channel 中读取数据时,如果没有其他 Goroutine 在相同 Channel 上等待写入,读取操作会被阻塞。
代码示例:
立即学习“go语言免费学习笔记(深入)”;
package main import "fmt" func main() { ch := make(chan int) // 创建一个无缓冲 Channel go func() { fmt.Println("开始写入数据") ch <- 1 // 写入数据到 Channel fmt.Println("数据写入成功") }() fmt.Println("等待读取数据") data := <-ch // 从 Channel 读取数据 fmt.Println("读取到数据:", data) }
在上述代码中,我们创建了一个无缓冲的 Channel ch。在 main 函数中,我们启动了一个 Goroutine,该 Goroutine 会向 Channel ch 写入数据。在主 Goroutine 中,我们试图从 Channel ch 中读取数据,由于没有其他 Goroutine 在此 Channel 上等待写入,读取操作会被阻塞。直到写入数据的 Goroutine 执行完成后,读取操作才会继续执行。
- 利用 select 语句实现非阻塞
除了利用 Channel 的长度实现阻塞和非阻塞之外,Golang 中还提供了 select 语句,使得我们可以更灵活地处理并发通信。
在 select 语句中,我们可以同时监听多个 Channel 的读取和写入操作。当一个或多个 Channel 准备好时,select 语句会随机选择一个可执行的操作进行执行。如果没有任何 Channel 准备好,那么 select 语句会进入阻塞状态,直到至少有一个 Channel 准备好。
代码示例:
立即学习“go语言免费学习笔记(深入)”;
package main import "fmt" func main() { ch1 := make(chan int) ch2 := make(chan int) go func() { ch1 <- 1 }() go func() { ch2 <- 2 }() fmt.Println("开始监听 Channel") select { case data := <-ch1: fmt.Println("从 ch1 中读取到数据:", data) case data := <-ch2: fmt.Println("从 ch2 中读取到数据:", data) } }
在上述代码中,我们创建了两个 Channel ch1 和 ch2,并分别启动了两个 Goroutine 分别向两个 Channel 中写入数据。在主 Goroutine 中,我们利用 select 语句从多个 Channel 中选择一个可执行的操作。由于两个 Channel 都已经准备好,select 语句会随机选择其中一个可执行的操作进行执行。
结论:
通过本文的介绍和代码示例,我们了解了 Golang Channels 的阻塞和非阻塞机制。在实际开发中,我们需要根据不同的需求和场景来选择合适的方式。无论是利用 Channel 的长度或是使用 select 语句,Golang 的并发通信机制都能够提供灵活而高效的并发处理能力。在编写并发程序时,我们应该深入理解阻塞和非阻塞的机制,合理地选择适当的处理方式,以确保程序的正确性和性能。
参考资料:
- https://gobyexample.com/channels
- https://go101.org/article/channel.html
(字数:819字)
以上就是Golang Channels 的阻塞和非阻塞机制解析的详细内容,更多请关注php中文网其它相关文章!
今天关于为什么Java中的FileChannel不是非阻塞的?和java filechannel原理的讲解已经结束,谢谢您的阅读,如果想了解更多关于08. Java NIO FileChannel 文件通道、8,Java NIO FileChannel、Apache的Flume和FileChannel有什么用、Golang Channels 的阻塞和非阻塞机制解析的相关知识,请在本站搜索。
本文标签: