2021-02-26

1.Java NIO简介
Java NIO(New IO)是一个可以替代标准Java IO API的IO API(从Java 1.4开始)。NIO与原来的IO有同样的作用和目的,但是使用的方式不同。NIO支持面向缓冲区的、基于通道的IO操作。NIO将以更高效的方式进行文件的读写操作。
IO与NIO区别:

1)Channels and Buffers(通道和缓冲区)
标准的IO基于字节流和字符流进行操作的,而NIO是基于通道(Channel)和缓冲区(Buffer)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。
通道表示打开IO设备(例如:文件)的连接。若需要使用NIO,需要获取用于连接IO设备的通道以及用于容纳数据的缓冲区。然后操作缓冲区,对数据进行处理。简而言之,Channel负责连接,Buffer负责存储
2) Non-blocking IO(非阻塞IO)
Java NIO可以让你非阻塞的使用IO,例如:当线程从通道读取数据到缓冲区时,线程还是可以进行其他事情。当数据被写入到缓冲区时,线程可以继续处理它。从缓冲区写入通道也类似。
3)Selectors(选择器)
Java NIO引入了选择器的概念,选择器用于监听多个通道的事件(比如:连接打开,数据到达。。。)。因此,单个的线程可以监听多个数据通道。
非阻塞IO和选择器主要是针对网络通信而言
2.Buffer
1)缓冲区,在Java NIO中负责数据的存取。缓冲区就是数组,用于存储不同数据,可以写入,可以读取
Java NIO里的Buffer类型:
ByteBuffer
CharBuffer
DoubleBuffer
FloatBuffer
IntBuffer
LongBuffer
ShortBuffer
MappedByteBuffer 表示内存映射文件
除了MappedByteBuffer之外,其他的操作方式基本上都是一致的,通过allocate()分配内存
2)Buffer的几个关键字段
capacity,position,limit,mark

position和limit的含义取决于Buffer处在读模式还是写模式。不管Buffer处在什么模式,capacity的含义总是一样的。
capacity:容量
作为一个内存块,Buffer有一个固定的大小值,也叫“capacity”.你只能往里写capacity个byte、long,char等类型。一旦Buffer满了,需要将其清空才能继续写数据往里写数据。
position:正在操作数据的位置
当你写数据到Buffer中时,position表示当前的位置。初始的position值为0.当一个byte、long等数据写到Buffer后,position会向后移动到下一个可插入数据的Buffer单元。position最大可为capacity – 1.
当将Buffer从写模式切换到读模式,position会被重置为0. 当从Buffer的position处读取数据时,position向后移动到下一个可读的位置。
limit:缓冲区中可以操作得数据的多少
在写模式下,Buffer的limit表示你最多能往Buffer里写多少数据。 limit等于Buffer的capacity
当切换Buffer到读模式时, limit表示你最多能读到多少数据。因此,当切换Buffer到读模式时,limit会被设置成你能读到之前写入的所有数据

3)Buffer的操作
① 分配内存:
ByteBuffer buf = ByteBuffer.allocate(48);//分配了一个48字节大小的ByteBuffer

② 写数据到Buffer:有两种方式
① 从Channel写到Buffer。
int bytesRead = inChannel.read(buf); //read into buffer.
② 通过Buffer的put()方法写到Buffer里。

③ flip()方法
flip方法将Buffer从写模式切换到读模式。调用flip()方法会将position设回0,并将limit设置成写状态下的position的值。
④ 从Buffer中读取数据:有两种方式
①从Buffer读取数据到Channel。
int bytesWritten = inChannel.write(buf);
②使用get()方法从Buffer中读取数据。

⑤ rewind()方法
Buffer.rewind()将position设回0,所以你可以重读Buffer中的所有数据
⑥ clear()与compact()方法
一旦读完Buffer中的数据,需要让Buffer准备好再次被写入。可以通过clear()或compact()方法来完成
clear()方法,position将被设回0,limit被设置成 capacity的值。Buffer中的数据并未清除,只是这些标记告诉我们可以从哪里开始往Buffer里写数据
compact()方法将所有未读的数据拷贝到Buffer起始处。然后将position设到最后一个未读元素正后面。limit属性依然像clear()方法一样,设置成capacity,现在Buffer准备好写数据了,但是不会覆盖未读的数据
⑦ mark()与reset()方法
通过调用Buffer.mark()方法,可以标记Buffer中的一个特定position。之后可以通过调用Buffer.reset()方法恢复到这个position。
4)直接缓冲区和非直接缓冲区
非直接缓冲区:通过allocate()方法分配缓冲区,将缓冲区建立在JVM内存中
直接缓冲区:通过allocateDirect() 方法或是FileChannel的map()方法分配直接缓冲区,将缓冲区建立在物理内存中

直接物理内存分配或是销毁消耗的资源大,而且我们不能控制将物理内存的数据何时存到磁盘上,一般情况下,仅在直接缓冲区能在程序性能方面带来明显好处时分配它
3.Channel
用于源节点和目标节点的连接。在Java NIO中负责缓冲区中数据的传输。Channel本身不能存储数据,需要配合缓冲区进行传输,可以从通道读取数据到缓冲区,也可以从缓冲区写入数据到通道
完全独立的处理器(不依赖CPU),专门用于处理IO
1)主要Channel的实现:
FileChannel 从本地文件中读写数据,FileChannel无法设 置为非阻塞模式,它总是运行在阻塞模式下。
DatagramChannel 能通过UDP读写网络中的数据
SocketChannel 通过TCP读写网络中的数据
ServerSocketChannel 监听新进来的TCP连接,像Web服务器那 样。对每一个新进来的连接都会创建一个 SocketChannel
2)获取通道
①Java针对支持通道的类提供了getChannel()方法
本地IO
FileInputStream/FileOutputStream
RandomAccessFile 对随机访问文件的读取和写入
网络IO
Socket
ServerSocket
DatagramSocket
②在JDK 1.7 中的NIO.2 针对各个通道提供了静态方法open()
③在JDK 1.7 中的NIO.2 的Files工具类的newByteChannel()

//利用通道完成文件的复制(非直接缓冲区)

//使用内存映射文件完成文件的复制(直接缓存区,等同于allocateDirect())

3)通道之间的传输(直接缓存区)
transferFrom()
transferTo()

4.NIO阻塞和非阻塞

在客户端和服务端之间放置选择器,每一个通道都会注册到选择器上,选择器会实时监控通道的IO状况,当通到的某个事件完全准备就绪时,选择器才会把任务分配到服务端的一个或多个线程上。当事件没有完全准备就绪时,线程可以做其他的事情,可以更有效的利用cpu的资源。

5.Selector 选择器
是Java NIO中能够检测一到多个NIO通道,并能够知晓通道是否为诸如读写事件做好准备的组件。这样,一个单独的线程可以管理多个channel,从而管理多个网络连接。
仅用单个线程来处理多个Channels的好处是,只需要更少的线程来处理通道。事实上,可以只用一个线程处理所有的通道。对于操作系统来说,线程之间上下文切换的开销很大,而且每个线程都要占用系统的一些资源(如内存)。因此,使用的线程越少越好。
Selector允许单线程处理多个 Channel。如果你的应用打开了多个连接(通道),但每个连接的流量都很低,使用Selector就会很方便。例如,在一个聊天服务器中。
一个单线程中使用一个Selector处理3个Channel的图:

1)Selector的创建
Selector selector = Selector.open();
2)向Selector注册通道
channel.configureBlocking(false);//设置为非阻塞模式
//将通道注册给选择器
SelectionKey key = channel.register(selector,Selectionkey.OP_READ);
与Selector一起使用时,Channel必须处于非阻塞模式下。这意味着不能将FileChannel与Selector一起使用,因为FileChannel不能切换到非阻塞模式
register()方法的第二个参数。这是一个“interest集合”,意思是在通过Selector监听Channel时对什么事件感兴趣。可以监听四种不同类型的事件:
Connect
Accept
Read
Write
通道触发了一个事件意思是该事件已经就绪。所以,某个channel成功连接到另一个服务器称为“连接就绪”(SelectionKey.OP_CONNECT)。一个Server socket channel准备好接收新进入的连接称为“接收就绪”(SelectionKey.OP_ACCEPT)。一个有数据可读的通道可以说是“读就绪”(SelectionKey.OP_READ)。等待写数据的通道可以说是“写就绪”(SelectionKey.OP_WRITE)。
如果你对不止一种事件感兴趣,那么可以用“位或”操作符将常量连接起来
int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE;

3)通过Selector选择通道
一旦向Selector注册了一或多个通道,就可以调用几个重载的select()方法。这些方法返回你所感兴趣的事件(如连接、接受、读或写)已经准备就绪的那些通道。换句话说,如果你对“读就绪”的通道感兴趣,select()方法会返回读事件已经就绪的那些通道。
6.SocketChannel和ServerSocketChannel
SocketChannel是一个连接到TCP网络套接字的通道。可以通过以下2种方式创建SocketChannel:
① 打开一个SocketChannel并连接到互联网上的某台服务器。
② 一个新连接到达ServerSocketChannel时,会创建一个SocketChannel
非阻塞模式
可以设置 SocketChannel 为非阻塞模式(non-blocking mode).设置之后,就可以在异步模式下调用connect(), read() 和write()了。

ServerSocketChannel是一个可以监听新进来的TCP连接的通道, 就像标准IO中的ServerSocket一样。ServerSocketChannel类在 java.nio.channels包中。
非阻塞模式
ServerSocketChannel可以设置成非阻塞模式。在非阻塞模式下,accept() 方法会立刻返回

①阻塞式网络通信

②非阻塞式网络通信

  1. NIO 与IO的主要区别
    IO NIO
    面向流 面向缓冲区
    阻塞IO 非阻塞IO
    无 选择器
    1)Java IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。此外,它不能前后移动流中的数据。如果需要前后移动从流中读取的数据,需要先将它缓存到一个缓冲区。Java NIO的缓冲导向方法略有不同。数据读取到一个它稍后处理的缓冲区,需要时可在通道中前后移动。
    2)Java IO的各种流是阻塞的。这意味着,当一个线程调用read() 或 write()时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了
    3)Java NIO的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取。而不是保持线程阻塞,所以直至数据变的可以读取之前,该线程可以继续做其他的事情。非阻塞写也是如此,一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。 线程通常将非阻塞IO的空闲时间用于在其它通道上执行IO操作,所以一个单独的线程现在可以管理多个输入和输出通道(channel)
    4)如果需要管理同时打开的成千上万个连接,这些连接每次只是发送少量的数据,例如聊天服务器,实现NIO的服务器可能是一个优势
    同样,如果你需要维持许多打开的连接到其他计算机上,如P2P网络中,使用一个单独的线程来管理你所有出站连接,可能是一个优势。
    如果你有少量的连接使用非常高的带宽,一次发送大量的数据,也许典型的IO服务器实现可能非常契合
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
2021-03-26 20:54:33,596 - Model - INFO - Epoch 1 (1/200): 2021-03-26 20:57:40,380 - Model - INFO - Train Instance Accuracy: 0.571037 2021-03-26 20:58:16,623 - Model - INFO - Test Instance Accuracy: 0.718528, Class Accuracy: 0.627357 2021-03-26 20:58:16,623 - Model - INFO - Best Instance Accuracy: 0.718528, Class Accuracy: 0.627357 2021-03-26 20:58:16,623 - Model - INFO - Save model... 2021-03-26 20:58:16,623 - Model - INFO - Saving at log/classification/pointnet2_msg_normals/checkpoints/best_model.pth 2021-03-26 20:58:16,698 - Model - INFO - Epoch 2 (2/200): 2021-03-26 21:01:26,685 - Model - INFO - Train Instance Accuracy: 0.727947 2021-03-26 21:02:03,642 - Model - INFO - Test Instance Accuracy: 0.790858, Class Accuracy: 0.702316 2021-03-26 21:02:03,642 - Model - INFO - Best Instance Accuracy: 0.790858, Class Accuracy: 0.702316 2021-03-26 21:02:03,642 - Model - INFO - Save model... 2021-03-26 21:02:03,643 - Model - INFO - Saving at log/classification/pointnet2_msg_normals/checkpoints/best_model.pth 2021-03-26 21:02:03,746 - Model - INFO - Epoch 3 (3/200): 2021-03-26 21:05:15,349 - Model - INFO - Train Instance Accuracy: 0.781606 2021-03-26 21:05:51,538 - Model - INFO - Test Instance Accuracy: 0.803641, Class Accuracy: 0.738575 2021-03-26 21:05:51,538 - Model - INFO - Best Instance Accuracy: 0.803641, Class Accuracy: 0.738575 2021-03-26 21:05:51,539 - Model - INFO - Save model... 2021-03-26 21:05:51,539 - Model - INFO - Saving at log/classification/pointnet2_msg_normals/checkpoints/best_model.pth 我有类似于这样的一段txt文件,请你帮我写一段代码来可视化这些训练结果
最新发布
02-06
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大猩猩乔治

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值