BIO、NIO

开源全闪存系统:Intel DAOS架构介绍 架构图管理节点:Admin Node,用于部署管理工具dmg,通过DAOS Mgmnt API访问。客户端节点:Client Node存储节点:Storage Node这三类节点都可以部署在物理节点,虚拟机或者容器中(node/vm/container)。Control Plane:Control Plane是系统的控制面或者管理面,用golang语言开发。客户端和服务端之间用基于tcp/ip的gRPC通信。和对应本机上Data Plane组件通过基于Unix Socker的dRPC通信。 阅读详情

OSI 网络七层模型

介绍

为使不同计算机厂家的计算机能够互相通信,以便在更大的范围内建立计算机网络,有必要建立一个国际范围的网络体系结构的标准。

组成

  1. 低三层,开发人员一般不用关注

    物理层:使原始的数据比特流在物理介质上传输。

    数据链路层:通过校验、确认和反馈重发等手段,形成稳定的数据链路。(01010101)

    网络层:进行路由选择和流量控制。(IP协议)

  2. 传输层

    提供可靠的端口到端口的数据传输服务(TCP/UDP协议)。

  3. 高三层,一般是web容器做的事情,比如Tomcat

    会话层:负责建立、管理和终止进程之间的会话和数据交换

    表示层:负责数据格式转换、数据加密与解密、压缩与解压等。

    应用层:为用户的应用进程提供网络服务。

TCP 、UDP

TCP

TCP提供面向连接、可靠、有序、字节流传输服务。应用程序在使用TCP之前,必须先建立TCP连接。建立连接需要三次握手、释放连接需要四次挥手。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wOn2LuFr-1648198220574)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20220226103608337.png)]

UDP

用户数据报协议UDP是Internet传输层协议。提供无连接、不可靠、数据报尽力传输服务。数据格式比较简单。针对ip和端口有目的地的发送,具有如下几个特点:

  1. 应用进程更容易控制发送数据以及何时发送(如TCP需要建立连接,连接成功时长受网络影响不可控)
  2. 无需要建立连接
  3. 无连接状态
  4. 首部开销小 源端口

TCP 和UDP比较

TCPUDP
面向链接无连接
提供可靠性保证不保证
慢快
资源占用多资源占用少

Soket编程

调用过程

创建套接字=>端点绑定=>发送数据=>接收数据=>释放套接字

Socket API函数定义

服务端: listen()、accept()

客户端:connect()

两端通用函数:socket()、bind()、send()、recv()、sendto()、recvfrom()、close()

BIO

介绍

  • 阻塞I/O(blocking I/O)模型,进程调用recvfrom,其系统调用直到数据报到达且被拷贝到应用进程的缓冲区中或者发生错误才返回。进程从调用recvfrom开始到它返回的整段时间内是被阻塞的。

    **阻塞调用是指调用结果返回之前,当前线程会被挂起。**调用线程只有在得到结果之后才会返回,阻塞导致在处理网络I/O时,一个线程只能处理一个网络连接,造成资源极大的浪费。

    阻塞I/O 模型

BIO即阻塞I/O,不管是磁盘I/O还是网络I/O,数据在写入OutputStream或者从InputStream读取时都有可能会阻塞,一旦有阻塞,线程将会失去CPU的使用权,这在当前的大规模访问量和有性能要求的情况下是不能被接受的。虽然当前的网络I/O有一些解决办法,如一个客户端一个处理线程,出现阻塞时只是一个线程阻塞而不会影响其他线程工作,还有为了减少系统线程的开销,采用线程池的办法来减少线程创建和回收的成本,但是有一些使用场景下仍然是无法解决的。

传统Socket阻塞案例代码

网络编程的基本模型是C/S模型,即两个进程间的通信。
服务端提供IP和监听端口,客户端通过连接操作想服务端监听的地址发起连接请求,通过三次握手连接,如果连接成功建立,双方就可以通过套接字进行通信。
传统的同步阻塞模型开发中,ServerSocket负责绑定IP地址,启动监听端口;Socket负责发起连接操作。连接成功后,双方通过输入和输出流进行同步阻塞式通信。
简单的描述一下BIO的服务端通信模型:采用BIO通信模型的服务端,通常由一个独立的Acceptor线程负责监听客户端的连接,它接收到客户端连接请求之后为每个客户端创建一个新的线程进行链路处理没处理完成后,通过输出流返回应答给客户端,线程销毁。即典型的一请求一应答通宵模型。

public class BIOClient {
	private static Charset charset = Charset.forName("UTF-8");
	public static void main(String[] args) throws Exception {
		Socket s = new Socket("localhost", 8080);
		OutputStream out = s.getOutputStream();
		Scanner scanner = new Scanner(System.in);
		System.out.println("请输入:");
		String msg = scanner.nextLine();
		out.write(msg.getBytes(charset)); // 阻塞,写完成
		scanner.close();
		s.close();
	}
}
/****
 * BIOServer 由于reader.readLine() 是阻塞的,启动多个BIOClient,只能处理完第一个才能接下来处理其他的,如果第一个没有处理完第二个连接会阻塞到
 * serverSocket.accept()处
 */
public class BIOServer {
    public static void main(String[] args) throws Exception {
        ServerSocket serverSocket = new ServerSocket(8080);
        System.out.println("服务器启动成功");
        while (!serverSocket.isClosed()) {
            Socket request = serverSocket.accept();//等待接收连接阻塞
            System.out.println("收到新连接 : " + request.toString());
            try {
                // 接收数据、打印
                InputStream inputStream = request.getInputStream(); // net + i/o
                BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
                String msg;
                while ((msg = reader.readLine()) != null) { // 没有数据,阻塞
                    if (msg.length() == 0) {
                        break;
                    }
                    System.out.println(msg);
                }
                System.out.println("收到数据,来自:"+ request.toString());
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    request.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        serverSocket.close();
    }
}

该模型最大的问题是,BIOServer是同时只能处理一个BIOCient请求,比如启动两个BIOClient去连接BIOServer,只有第一个完成处理,第二个才能被连接处理,当第一个连接上的BIOClient没有处理完,比如客户端没有输入内容,reader.readLine()因获取不到内容被阻塞,第二个连接会被阻塞在serverSocket.accept()处

伪异步I/O

为了改进这种一连接一线程的模型,我们可以使用线程池来管理这些线程,实现1个或多个线程处理N个客户端的模型(但是底层还是使用的同步阻塞I/O),通常被称为“伪异步I/O模型”。

// 多线程支持,一个线程处理一个BIOClient
public class BIOServer1 {
    private static ExecutorService threadPool = Executors.newCachedThreadPool();
    public static void main(String[] args) throws Exception {
        ServerSocket serverSocket = new ServerSocket(8080);
        System.out.println("tomcat 服务器启动成功");
        while (!serverSocket.isClosed()) {
            Socket request = serverSocket.accept();
            System.out.println("收到新连接 : " + request.toString());
            threadPool.execute(() -> {
                try {
                    // 接收数据、打印
                    InputStream inputStream = request.getInputStream();
                    BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
                    String msg;
                    while ((msg = reader.readLine()) != null) { // 阻塞
                        if (msg.length() == 0) {
                            break;
                        }
                        System.out.println(msg);
                    }
                    System.out.println("收到数据,来自:"+ request.toString());
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    try {
                        request.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
        serverSocket.close();
    }
}

使用线程池一个线程处理一个客户端的请求,多个客户端请求互不影响。

加入 http协议 ,返回http内容

以上代码并不能支持数据返回给浏览器,虽然浏览器可以请求到对应对应的服务,但是并不支持数据返回,因为没有加入http协议.

public class BIOServer2 {

    private static ExecutorService threadPool = Executors.newCachedThreadPool();

    public static void main(String[] args) throws Exception {
        ServerSocket serverSocket = new ServerSocket(8080);
        System.out.println("服务器启动成功");
        while (!serverSocket.isClosed()) {
            Socket request = serverSocket.accept();
            System.out.println("收到新连接 : " + request.toString());
            threadPool.execute(() -> {
                try {
                    // 接收数据、打印
                    InputStream inputStream = request.getInputStream();
                    BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
                    String msg;
                    while ((msg = reader.readLine()) != null) {
                        if (msg.length() == 0) {
                            break;
                        }
                        System.out.println(msg);
                    }

                    System.out.println("收到数据,来自:"+ request.toString());
                    // 响应结果 200
                    OutputStream outputStream = request.getOutputStream();
                    outputStream.write("HTTP/1.1 200 OK\r\n".getBytes());
                    outputStream.write("Content-Length: 11\r\n\r\n".getBytes());
                    outputStream.write("Hello World".getBytes());
                    outputStream.flush();
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    try {
                        request.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
        serverSocket.close();
    }
}

只需要在返回的时候加入http对应的返回协议即可返回数据给浏览器

请求数据包解析 请求数据包解析 响应状态码

阻塞、非阻塞、同步、非同步

1.同步和异步

同步:在发出一个同步调用时,在没有得到结果之前,该调用就不返回。

异步:在发出一个异步调用后,调用者不会立刻得到结果,该调用就返回了。

2.阻塞与非阻塞

阻塞调用是指调用结果返回之前,调用者会进入阻塞状态等待。只有在得到结果之后才会返回。

非阻塞调用是指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回。

阻塞调用:比如 socket 的 recv(),调用这个函数的线程如果没有数据返回,它会一直阻塞着,也就是 recv() 后面的代码都不会执行了,程序就停在 recv() 这里等待,所以一般把 recv() 放在单独的线程里调用。

非阻塞调用:比如非阻塞socket 的 send(),调用这个函数,它只是把待发送的数据复制到TCP输出缓冲区中,就立刻返回了,线程并不会阻塞,数据有没有发出去 send() 是不知道的,不会等待它发出去才返回的。

同步的定义看起来跟阻塞很像,但是同步跟阻塞是两个概念,同步调用的时候,线程不一定阻塞,调用虽然没返回,但它还是在运行状态中的,CPU很可能还在执行这段代码,而阻塞的话,它就肯定不在CPU中跑这个代码了。这就是同步和阻塞的区别。同步是肯定可以在,阻塞是肯定不在。

异步和非阻塞的定义比较像,两者的区别是异步是说调用的时候结果不会马上返回,线程可能被阻塞起来,也可能不阻塞,两者没关系。非阻塞是说调用的时候,线程肯定不会进入阻塞状态。

上面两组概念,就有4种组合。

同步阻塞调用:得不到结果不返回,线程进入阻塞态等待。

同步非阻塞调用:得不到结果不返回,线程不阻塞一直在CPU运行。

异步阻塞调用:去到别的线程,让别的线程阻塞起来等待结果,自己不阻塞。

异步非阻塞调用:去到别的线程,别的线程一直在运行,直到得出结果。

NIO

Channel和Selector,它们是NIO中的两个核心概念。我们仍用前面的城市交通工具来继续比喻NIO的工作方式,这里的Channel要比Socket更加具体,它可以比做某种具体的交通工具,如汽车或高铁,而Selector可以比做一个车站的车辆运行调度系统,它将负责监控每辆车的当前运行状态,是已经出战,还是在路上等。也就是它可以轮询每个Channel的状态。当我们调用write()往SendQ中写数据时,当一次写的数据超过SendQ长度时需要按照SendQ的长度进行分割,这个过程中需要将用户空间数据和内核地址空间进行切换,而这个切换不是你可以控制的,但在Buffer中我们可以控制Buffer的容量、是否扩容以及如何扩容.

Selector 一般称 为选择器 ,当然你也可以翻译为 多路复用器 。它是Java NIO核心组件中的一个,用于检查一个或多个NIO Channel(通道)的状态是否处于可读、可写。如此可以实现单线程管理多个channels,也就是可以管理多个网络链接。

使用Selector的好处在于: 使用更少的线程来就可以来处理通道了, 相比使用多个线程,避免了线程上下文切换带来的开销。

Selector Server端原理

Selector的静态工厂创建一个选择器,创建一个服务端的Channel,绑定到一个Socket对象,并把这个通信信道注册到选择器上,把这个通信信道设置为非阻塞模式。然后就可以调用Selector的selectedKeys方法来检查已经注册在这个选择器上的所有通信信道是否有需要的事件发生,如果有某个事件发生,将会返回所有的SelectionKey,通过这个对象Channel方法就可以取得这个通信信道对象,从而可以读取通信的数据,而这里读取的数据是Buffer,这个Buffer是我们可以控制的缓冲器。

NIO是同步阻塞的

我们知道java nio是基于io多路复用模型,也就是我们经常提到的select,poll,epoll。io 多路复用本质是同步io,其需要调用方在读写事件就绪时主动去进行读写。在java nio中,通过selector来获取就绪的事件,当selector上监听的channel中没有就绪的读写时间时,其可以直接返回,或者设置一段超时后返回。可以看出java nio可以实现非则塞,而不像传统io里必须则塞当前线程直到可读或可写。所以,java nio可以实现非阻塞。

NIO 核心组件

Buffer缓冲区

缓存区本质上是一个可以写入数据的内存块(类似数组),然后可以再次读取。此内存块包含在NIO Buffer对象中,该对象提供一组方法,可以轻松的使用内存块。

Buffer三个重要属性:

capacity容量: 作为一个内存块,Buffer具有一定的固定大小,也称为 容量.

positiion位置:写入模式时代表写数据的位置。读取模式时代表读取数据的位置。

limit限制: 写入模式,限制等于buffer的容量。读取模式下,limit等于写入的数据量

flip:在写模式下调用flip方法,那么limit就设置为了position当前的值(即当前写了多少数据),postion会被置为0,以表示读操作从缓存的头开始读。

Channel通道

和标准IO Stream 操作的区别: 在一个通道内进行读取和写入,stream通常是单向的(input或output),可以非阻塞读取和写入通道,通道始终读取和写入缓冲区。

SocketChannel:用于建立TCP网络连接,类似java.net.Socket.有两种创建socketChannel形式:

  1. 客户端主动发起和服务器的连接

    SocketChannel socketChannel = SocketChannel.open();
    socketChannel.configureBlocking(false);
    socketChannel.connect(new InetSocketAddress("127.0.0.1", 8080));
    
  2. 服务端获取新的连接

    SocketChannel socketChannel = serverSocketChannel.accept(); // 获取新tcp连接通道
    

write写:write()在尚未写入任何内容时就可能返回了。需要再循环中调用write().

read读: read()方法可能直接返回而根本不读取任何数据,根据返回的int值判断读取了多少字节。

ServerSocketChannel:可以监听新建的TCP连接通道,类似ServerSocket。

serverSocketChannel.accept():如果该通道处于非阻塞模式,那么如果没有挂起的连接,该方法立即返回null。必须检查返回的SocketChannel是否为null。

Selector选择器

Selector是一个Java NIO组件,可以检查一个或多个NIO通道,并确定哪些通道已准备好进行读取或写入。实现单个线程可以管理多个通道,从而管理多个网络连接。

一个线程使用Selector监听多个channel的不同事件:

四个事件分别对应SelectionKey四个常量.

  1. Connect连接(SelectionKey.OP_CONNECT)
  2. Accept准备就绪(OP_ACCEPT)
  3. Read读取(OP_READ)
  4. Write写入(OP_WRITE)

实现一个线程处理多个通道的核心概念理解:事件驱动机制.

非阻塞的网络通道下,开发者通过Selector注册对于通道感兴趣的事件类型,线程通过监听事件来触发相应的代码执行。(拓展:更底层是操作系统的多路复用机制)

selector相关方法说明

selector.select()//阻塞 ,监控所有注册的通道,当其中有IO操作可以进行时,将对应的SelectionKey加入到内部集合中并返回,参数用来设置超时时间,如果不设置超时时间 ,注册的事件至少有一个通道发生才返回,否则一直阻塞。

selector.select(1000);//阻塞 1000 毫秒,在 1000 毫秒后返回,不管监听的通道是否有事件发生。

selector.wakeup();//唤醒 selector ,唤醒阻塞的selector

selector.selectNow();//不阻塞,立马返还;不进行阻塞立即返回

NIO对比BIO

BIO:阻塞IO,线程等待时间长,一个线程负责一个连接处理,线程多且利用率低

NIO:非阻塞IO,线程利用率更高,一个线程处理多个连接事件,性能更强大。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FLg19wGB-1648198220578)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20220313211119238.png)]

NIO 代码示例

NIO Client demo

public class NIOClient {
    public static void main(String[] args) throws  Exception{
        SocketChannel socketChannel=SocketChannel.open();
        socketChannel.configureBlocking(false);//设置为非阻塞模式
        socketChannel.connect(new InetSocketAddress("127.0.0.1",8080));
        while (!socketChannel.finishConnect()){
            //没连接上 则一直等待
            Thread.yield();
        }
        Scanner scanner=new Scanner(System.in);
        System.out.println("请输入");
        //发送内容
        String msg=scanner.nextLine();
        ByteBuffer buffer=ByteBuffer.wrap(msg.getBytes());
        while (buffer.hasRemaining()){//表示读取完毕
            socketChannel.write(buffer);
        }
        //读取相应
        System.out.println("收到服务端响应:");
        ByteBuffer reqeustBuffer=ByteBuffer.allocate(1024);
        while (socketChannel.isOpen() && socketChannel.read(reqeustBuffer)!=-1){
            //长链接情况下,需要手动判断数据有没有读取结束(此处做一个简单的判断:超过0字节就认为请求结束了)
           if(reqeustBuffer.position()>0)break;;
        }
        reqeustBuffer.flip();//从头开始读取
        byte[]content=new byte[reqeustBuffer.limit()];
        reqeustBuffer.get(content); //读取数据到byte[]数组中
        System.out.println(new String(content));
        scanner.close();;
        socketChannel.close();
    }
}
/**
 * 直接基于非阻塞的写法
 */
public class NIOServer {
    public static void main(String[] args) throws Exception {
        // 创建网络服务端
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.configureBlocking(false); // 设置为非阻塞模式
        serverSocketChannel.socket().bind(new InetSocketAddress(8080)); // 绑定端口
        System.out.println("启动成功");
        while (true) {
            SocketChannel socketChannel = serverSocketChannel.accept(); // 获取新tcp连接通道
            // tcp请求 读取/响应
            if (socketChannel != null) {
                System.out.println("收到新连接 : " + socketChannel.getRemoteAddress());
                socketChannel.configureBlocking(false); // 默认是阻塞的,一定要设置为非阻塞
                try {
                    ByteBuffer requestBuffer = ByteBuffer.allocate(1024);
                    while (socketChannel.isOpen() && socketChannel.read(requestBuffer) != -1) {
                        // 长连接情况下,需要手动判断数据有没有读取结束 (此处做一个简单的判断: 超过0字节就认为请求结束了)
                        if (requestBuffer.position() > 0) break;
                    }
                    if(requestBuffer.position() == 0) continue; // 如果没数据了, 则不继续后面的处理
                    requestBuffer.flip();
                    byte[] content = new byte[requestBuffer.limit()];
                    requestBuffer.get(content);
                    System.out.println(new String(content));
                    System.out.println("收到数据,来自:"+ socketChannel.getRemoteAddress());

                    // 响应结果 200
                    String response = "HTTP/1.1 200 OK\r\n" +
                            "Content-Length: 11\r\n\r\n" +
                            "Hello World";
                    ByteBuffer buffer = ByteBuffer.wrap(response.getBytes());
                    while (buffer.hasRemaining()) {
                        socketChannel.write(buffer);// 非阻塞
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        // 用到了非阻塞的API, 在设计上,和BIO可以有很大的不同.继续改进
    }
}
/**
 * 结合Selector实现的非阻塞服务端(放弃对channel的轮询,借助消息通知机制)
 */
public class NIOServerV2 {
    public static void main(String[] args) throws Exception{
        // 1. 创建网络服务端ServerSocketChannel
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.configureBlocking(false); // 设置为非阻塞模式

        // 2. 构建一个Selector选择器,并且将channel注册上去
        Selector selector=Selector.open();
        SelectionKey selectionKey=serverSocketChannel.register(selector,0,serverSocketChannel);//将serverSocketChannel注册到selector
        selectionKey.interestOps(SelectionKey.OP_ACCEPT); // 对serverSocketChannel上面的accept事件感兴趣(serverSocketChannel只能支持accept操作)

        // 3. 绑定端口
        serverSocketChannel.socket().bind(new InetSocketAddress(8080));
        System.out.println("启动成功");

        while (true){
            // 不再轮询通道,改用下面轮询事件的方式.select方法有阻塞效果,直到有事件通知才会有返回
            selector.select();
            //获取事件
            Set<SelectionKey> selectionKeys=selector.selectedKeys();
            // 遍历查询结果
            Iterator<SelectionKey> iter = selectionKeys.iterator();
            while (iter.hasNext()){
                //被分装的查询结果
                SelectionKey key=iter.next();
                iter.remove();
                //关注Read和Accept两个事件
                if(key.isAcceptable()){
                    ServerSocketChannel server = (ServerSocketChannel) key.attachment();
                    // 将拿到的客户端连接通道,注册到selector上面
                    SocketChannel clientSocketChannel = server.accept(); // mainReactor 轮询accept
                    clientSocketChannel.configureBlocking(false);
                    clientSocketChannel.register(selector, SelectionKey.OP_READ, clientSocketChannel);//accept之后再次注册read事件
                    System.out.println("收到新连接 : " + clientSocketChannel.getRemoteAddress());
                }
                if(key.isReadable()){
                    SocketChannel socketChannel = (SocketChannel) key.attachment();
                    try{
                        ByteBuffer requestBuffer = ByteBuffer.allocate(1024);
                        while (socketChannel.isOpen() && socketChannel.read(requestBuffer) != -1) {
                            // 长连接情况下,需要手动判断数据有没有读取结束 (此处做一个简单的判断: 超过0字节就认为请求结束了)
                            if (requestBuffer.position() > 0) break;
                        }
                        if(requestBuffer.position() == 0) continue; // 如果没数据了, 则不继续后面的处理
                        requestBuffer.flip();
                        byte[] content = new byte[requestBuffer.limit()];
                        requestBuffer.get(content);
                        System.out.println(new String(content));
                        System.out.println("收到数据,来自:" + socketChannel.getRemoteAddress());
                        // TODO 业务操作 数据库 接口调用等等

                        // 响应结果 200
                        String response = "HTTP/1.1 200 OK\r\n" +
                                "Content-Length: 11\r\n\r\n" +
                                "Hello World";
                        ByteBuffer buffer = ByteBuffer.wrap(response.getBytes());
                        while (buffer.hasRemaining()) {
                            socketChannel.write(buffer);
                        }

                    }catch (IOException e) {
                        // e.printStackTrace();
                        key.cancel(); // 取消事件订阅
                    }
                }
            }
             // 过掉cancelled keys
            selector.selectNow();
        }
        // 问题: 此处一个selector监听所有事件,一个线程处理所有请求事件. 会成为瓶颈! 要有多线程的运用
    }
}

NIO存在的问题

  1. NIO 的类库和 API 繁杂,使用麻烦:需要熟练掌握 Selector、ServerSocketChannel、SocketChannel、ByteBuffer

等。

  1. 需要具备其他的额外技能:要熟悉 Java 多线程编程,因为 NIO 编程涉及到 Reactor 模式,你必须对多线程

和网络编程非常熟悉,才能编写出高质量的 NIO 程序。

  1. 开发工作量和难度都非常大:例如客户端面临断连重连、网络闪断、半包读写、失败缓存、网络拥塞和异常流

的处理等等。

  1. JDK NIO 的 Bug:例如臭名昭著的 Epoll Bug,它会导致 Selector 空轮询,最终导致 CPU 100%。直到 JDK 1.7

版本该问题仍旧存在,没有被根本解决。

【DAOS】Intel DAOS 分布式异步对象存储|Architecture Overview|架构概述 目录 前言 什么是DAOS 为什么要用DAOS 1架构概述 1.1专业术语和缩写 1.2架构 1.2.1DAOS 特性 1.2.2DAOS 系统 1.2.3SDK 和 Tools 1.2.4 代理Agent 1.3存储模型(Storage Model) 1.3.1 DAOS Pool 1.3.2 DAOS Container... 阅读详情

相关推荐

BIO、NIO、AIO

Java BIO 就是传统的 java io 编程,其相关的类和接口在 java.ioBIO(blocking I/O) : 同步阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,可以通过线程池机制改善(实现多个客户连接服务器).​ 在上述的案例中,一个服务端只能接收一个客户端的通信请求,那么如果服务端需要处理很多个客户端的消息通信请求应该如何处理呢​ 在上述案例中:客户端的并发访问增加时。

我爱写代码 我爱写代码 我爱写代码 1393

BIO,NIO,AIO区别

BIO,NIO,AIO 总结 Java 中的 BIO、NIO和 AIO 理解为是 Java 语言对操作系统的各种 IO 模型的封装。程序员在使用这些 API 的时候,不需要关心操作系统层面的知识,也不需要根据不同操作系统编写不同的代码。只需要使用Java的API就可以了。 在讲 BIO,NIO,AIO 之前先来回顾一下这样几个概念:同步与异步,阻塞与非阻塞。 同步与异步 同步:同步就是发起一个调用后,被调用者未处理完请求之前,调用不返回。 异步:异步就是发起一个调用后,立刻得到被调..

Meiko记录 2万+

使用Matlab进行IEEE 33节点潮流计算的NR法实现详解及应用实例

IEEE 33节点系统是一个标准的配电系统模型,广泛用于学术研究和工程应用。该系统由33个节点和37条线路组成,结构复杂,具有代表性。其潮流计算结果可用于验证各种潮流计算方法的准确性和效率。NR法是一种基于迭代求解的潮流计算方法,通过不断迭代求解非线性方程组,直到达到预定的收敛条件。NR法具有收敛速度快、计算精度高的优点,适用于大规模复杂电力系统的潮流计算。

m0_57781768的博客 2071

BIO、NIO、AIO详解

一、Java的I/O演进之路 Java共支持3种网络编程的I/O模型:BIO、NIO、AIO BIO: 同步并阻塞(传统阻塞型),服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销 NIO: 同步非阻塞,服务器实现模式为一个线程处理多个请求(连接),即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求就进行处理 AIO: 异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求

hxt的博客 2万+

死区补偿---学习笔记

最近调试中发现,死区补偿对电流谐波和电流带宽影响挺大,于是对死区补偿产生浓厚兴趣,找来几篇文章粗读并做一下笔记。 传统做法 无非就是根据电流方向补偿,假如svpwm计算出的A相理论导通实践为T1,死区时间是Td,则实际导通时间T = T1-Td(when ia >0 ),于是在svpwm计算出的导通时间T1的基础上加上Td。这样经过PWM模块后,实际的导通时间即为T1. 但存在两个难点(个人总结): 1,受电流检测精度影响,尤其是在过零点检测困难。 2,真实的二极管导通需要一定电压,并非..

圆桌骑士的博客 2万+

AIGC内容溯源技术:如何追踪AI生成内容的原始来源

本文旨在系统性地介绍AIGC内容溯源的技术体系,帮助读者理解如何追踪AI生成内容的来源。我们将覆盖从基础概念到前沿技术的完整知识链,包括但不限于数字水印、区块链存证、内容指纹等技术方案。文章将从AIGC的基本概念出发,逐步深入探讨各种溯源技术,分析其原理和实现,最后讨论实际应用和未来趋势。AIGC:AI Generated Content,人工智能生成内容内容溯源:追踪数字内容的创作、修改和传播历史数字水印:嵌入在数字内容中的不可见识别信息数字水印:隐藏在内容中的识别信息,像隐形墨水内容指纹。

SuperAGI2025 2073

BIO和NIO的区别

1.BIO基本介绍 BIO是传统的Java IO编程,其基本的类和接口在java.io包中 BIO(blocking I/O):同步阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销 BIO方式使用于连接数目比较小且固定的架构,这种服务方式对服务器资源要求比价高,并且局限于应用中,JDK1.4以前的唯一选择,程序简单易理解 BIO基本模型: 2.NIO基本介绍 NIO全称 java non-blocking

炸酱面的博客 2万+

Windows 11“此应用已被管理员阻止运行”解决方案

通过本文介绍的两种方法,你应该能够解决Windows 11中“此应用已被管理员阻止运行”的问题。无论你选择创建新管理员账户还是禁用管理员批准模式,都请确保了解相关操作的风险,并根据你的实际需求做出选择。通过禁用“用户账户控制:以管理员批准模式运行所有管理员”设置,可以解决因系统安全设置导致的应用程序被阻止运行的问题。这种方法适用于那些希望简化管理员账户操作流程的用户,但需要注意可能带来的安全风险。通过创建并登录具有管理员权限的新账户,可以解决因系统安全设置导致的应用程序被阻止运行的问题。

mmoo_python的博客 1万+

BIO和NIO

简述BIO和NIO的原理和应用。提示:以下是本篇文章正文内容,下面案例可供参考最后用一个例子进行总结,在一节课堂中,服务端比作收作业的老师,客户端比作交作业的同学BIO: 老师先收A同学的作业,再去收B,C同学的作业,如果A同学一直做不完就不会去收B,C老师的试卷,虽然可以加几个老师去同时收作业,但是这样开销肯定会变大NIO: 老师这个时候不会因为A同学作业写不完而阻塞,而是继续去收一下同学的作业select/poll: 同学写完作业会举手,但是老师不知道是谁举的手,于是就把所有的同学轮询一遍。

qq_39239864的博客 981

Xinference新手指南(一个命令直接安装成功)

对于新手,必须得学会使用docker部署,这是基本功!这里就不过多去介绍了,如果评论要出教程的话,以后再出了。

Ven%的博客 820

044、手持视频抖动严重?OpenCV 光流 + IMU 融合的电子防抖工程方案

本文探讨了基于OpenCV光流和IMU融合的手持视频电子防抖方案。作者从实际工程经验出发,分析了纯光流和纯IMU方案的局限性,指出时间戳对齐和坐标系标定是关键挑战。文章详细介绍了融合滤波器的实现方法,推荐互补滤波替代卡尔曼滤波,并提出了动态调整融合系数的策略。在光流算法优化方面,建议采用网格化FAST特征点和前后向误差检测。最后分享了运动补偿裁剪策略和多线程流水线设计,强调在嵌入式设备上使用NEON指令优化性能。该方案通过精确的时间同步和传感器融合,有效解决了手持拍摄中的高频抖动问题。

ai技术增长的博客 252

BIO、NIO、AIO的区别

NIO(New I/O 或 Non-blocking I/O):使用非阻塞 I/O 模型,线程在等待 I/O 时可执行其他任务,通过 Selector 监控多个 Channel 上的事件,提高性能和可伸缩性,适用于高并发场景。异步非阻塞 I/O 模型:这种模式下,我们的工作模式是先来到厨房,开始烧水,我们不一直坐在水壶前面等,也不隔一段时间去看一下,而是在客厅看电视,水壶上面有个开关,水烧开之后他会通知我。IO,常写作 I/O,是 Input/Output 的简称,即输入/输出。最后,关闭文件通道。

wswpomos的博客 3735

MT4/MT5 第三代移动平均线(MetaTrader 指标)

第三代移动平均线(3G-MA)是传统MA指标的升级版本,通过"时滞压缩"算法将信号滞后降至理论极限(λ=2)。该指标在保留平滑性的同时,信号速度比EMA快1.5-2.3倍,适用于MT4/MT5平台。核心参数包括计算周期(默认34)、滞后压缩系数(2-10)和应用价位选择,支持斜率变色功能。安装简单,无需外部依赖,通过多周期共振可提升12-18%胜率。指标代码包含完整的MT4/MT5实现方案,采用双缓冲计算结构,通过相位前移算法抵消群延迟。风险提示:需配合其他技术指标和严格风控(≤2%账户

JanLEE 582

Java:什么是NIO?什么是BIO?NIO 和 BIO 有什么区别?

一、什么是NIO 1.概念 NIO是java1.4中引入的,被称为new I/O,也有说是non-blocking I/O,NIO被成为同步非阻塞的IO。 image.png 2.跟BIO流的区别 BIO是面向流的,NIO是面向块(缓冲区)的。 BIO的流都是同步阻塞的,而NIO是同步非阻塞的。 NIO会等待数据全部传输过来再让线程处理,BIO是直接让线程等待。 NIO有选择器,而BIO没有。 NIO是采用管道和缓存区的形式来处理数据的,而BIO是采

mifffy_java的博客 2006

华为OD机试 双机位C卷:微服务的集成测试 (C/C++/Py/Java/JS/Go)

华为OD机试 双机位C卷 :微服务的集成测试 ,提供C语言、Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解。华为OD机试 微服务的集成测试 , 华为OD 微服务的集成测试

qq_45776114的博客 2066

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

bio nio aio区别_8分钟深入浅出搞懂BIO、NIO、AIO

在高性能的IO体系设计中,BIO、NIO、AIO的概念,常常会让我们感到困惑不解。在Java面试中,我们也经常会被问到这个问题。譬如:BIO、NIO、AIO 的概念同步/异步、阻塞/非阻塞的区别NIO 如何实现多路复用功能AIO、BIO、NIO的适用场景NIO的核心概念、应用和框架等等这块内容本身比较复杂,很难用三言两语说明白,而书上的定义不太容易理解。本篇内容按照我的理解,以尽可能简单、易懂的语...

weixin_34501666的博客 8264

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

NIO BIO AIO

三种IO的区别BIO(Blocking I/O) :同步阻塞I/O模式 一个人只去厨房烧水且坐等烧水成功NIO(New I/O):同步非阻塞模式 一个人只去厨房烧水且不定期来查看(轮询)AIO (Asynchronous I/O):异步非阻塞 I/O 模型 一个人只去厨房烧水且去看电视且烧水成功之后有提醒// 使用 BIO 写入文件try {​bufferedWriter.write("学编程就上技术派");​System.out.println("写入完成");

xjd444的博客 1463

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

还不懂BIO,NIO,AIO吗

Channel(通道)、Buffer (缓存区)、Selector(选择器) Channel 类似于流,但是它是一个双向的流,他是连接服务端和客户端的通道,不管是客户端还是服务端,都可以使用通道进行读写数据。在NIO模型中,服务端可以开启一个线程处理多个连接,它是非阻塞的,客户端发送的数据都会注册到多路复用器selector上面,当selector (selector的select方法是阻塞的)轮询到有读、写或者连接请求时,才会转发到后端程序进行处理,没有数据的时候,业务程序并不需要阻塞等待。

qq_62097431的博客 1545

NIO和BIO的比较

NIO和BIO的比较1. NIO和BIO的比较2. NIO中三大组件关系2.1 Buffer2.2 Channel(通道)2.3 Buffer和Channel的注意事项和细节。2.4 Selector(选择器) 1. NIO和BIO的比较 BIO以流的方式处理数据,而NIO以块的方式处理数据,块I/O的效率比流I/O高很多。 BIO是阻塞的,NIO是非阻塞的 BIO基于字节流和字符流进行操作,而NIO是基于Channel(通道)和Buffer(缓冲区)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写

Yolyn‘s blog 5709

从BIO到NIO

NIO是如何从BIO引申过来的? 充分理解selector和ServerSocketChannel

weixin_45483328的博客 921
上一篇: Kafka踩坑记
下一篇: Linux系统下载并安装Redis
一切还来得及
博客等级 码龄11年 50粉丝 19原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值