Java中的I/O模型——BIO、NIO、AIO

1. BIO(Blocking I/O)

1. 1 BIO(Blocking I/O)模型概述

        BIO,即“阻塞I/O”(Blocking I/O),是一种同步阻塞的I/O模式。它的主要特点是,当程序发起I/O请求(比如读取数据或写入数据)时,程序会一直等到这个请求完成,才继续往下执行。在BIO模型下,每个连接都需要一个独立的线程去处理。

        举个简单的例子:假设你写了一个服务器,它会接收客户端的连接,并与客户端进行数据交流。在BIO模式下,这个服务器每接收一个连接,就需要新创建一个线程来处理该连接的数据读写。这意味着:

  • 如果有100个客户端同时连接服务器,服务器需要创建100个线程来处理。
  • 如果客户端不发送数据,线程就会空闲等待,但依旧会占用系统资源(例如CPU和内存)。

        这种模型对于连接数量较少连接时间较短的场景比较合适。但是如果连接数量增多,比如成千上万个连接,BIO模式就显得捉襟见肘了,因为线程数量会迅速增加,系统资源会被大量占用,最终导致性能下降。

1.2BIO的工作原理

        在BIO(Blocking I/O)模式中,关键的机制就是“阻塞”。简单来说,阻塞意味着当一个I/O操作(例如读取数据)在进行时,程序会“停下来”直到操作完成才能继续。让我们一步步来看一个BIO服务器的典型工作流程:

  1. 等待客户端连接:服务器启动后,会在某个端口上等待客户端的连接请求。

  2. 接收连接:当客户端发起连接时,服务器会接收该连接,并创建一个新的线程来处理这个连接。这个线程负责处理客户端发送过来的所有数据,直到连接关闭。

  3. 数据读取阻塞:一旦线程开始读取数据,它会进入阻塞状态,直到收到完整的数据或遇到异常。在这期间,线程不能做其他事情。想象成排队买票,一个窗口只能接待一个人,其他人都得等前一个人买完才能上前。

  4. 处理数据:当线程收到数据后,它会处理这些数据(例如解析请求、生成响应)。

  5. 发送数据阻塞:处理完数据后,线程会将响应发送给客户端。在发送过程中,线程也会被阻塞,直到数据全部发送完毕。

  6. 结束连接或继续等待:如果客户端断开连接,线程会关闭。如果客户端保持连接,线程会继续等待下一个数据块的到来。

        整个流程看似简单,但每一个连接都占用一个线程。所以,一旦连接数较多,系统资源就会迅速消耗,产生以下问题:

1.3 BIO的优缺点分析

优点

  1. 逻辑简单:BIO模型结构直观,每个线程专门服务一个客户端连接,代码编写和调试相对简单。

  2. 适合短连接:对于连接时间较短、交互少的场景(例如Web应用中的HTTP请求),BIO模型能胜任。

缺点

  1. 资源占用高:由于每个连接都需要一个线程来处理,线程数量直接与连接数成正比,导致资源消耗随连接数增加而大幅度提高。

  2. 性能瓶颈:线程之间需要竞争CPU时间片,同时可能会导致大量线程进入等待状态(因为阻塞I/O),从而降低CPU的整体利用率。

  3. 扩展性差:BIO模型并不适合需要处理大量并发连接的应用场景,比如实时聊天系统或大规模服务器。因为线程数受限于系统资源,过多的线程会拖慢系统响应速度,甚至导致崩溃。

2. NIO(Non-blocking I/O)

        NIO,全称非阻塞I/O(Non-blocking I/O),是Java在1.4版引入的一种新I/O模型,它通过非阻塞机制和多路复用(Selector)来管理大量的连接,目标是提高高并发下的性能。我们分步来看看NIO的特点和工作流程。

2.1 NIO的关键概念

  1. 非阻塞(Non-blocking):NIO允许线程在等待I/O操作时不用一直被“卡住”。比如,线程可以发起一个读取请求并立即返回,如果数据未准备好,线程可以先去做其他事,不会阻塞等待。

  2. 多路复用(Selector):NIO通过一个Selector来管理多个通道(Channel)和连接。Selector是一个事件管理器,能在同一线程中监控多个连接的状态,只有当某个连接有数据准备好时才处理该连接。这使得一个线程可以处理多个连接,节省了大量的资源。

2.2 NIO的核心组件

在NIO中,有几个核心组件我们需要理解:

  • Channel(通道):类似于BIO中的“流”,但Channel是双向的,即既能读又能写。常用的Channel包括SocketChannel(用于网络数据传输)、FileChannel(用于文件操作)等。

  • Buffer(缓冲区):在NIO中,数据读写都是通过缓冲区进行的。缓冲区是一个可以存放数据的内存区域,数据读写都会先进入缓冲区,再从缓冲区进行处理。

  • Selector(选择器)Selector负责监听多个Channel的状态,可以在一个线程内监控多个连接,只有当Channel有数据可读、可写或有新的连接时,Selector才会触发处理。

2.3 NIO的工作流程

让我们一步步看NIO是如何工作的:

  1. 创建通道(Channel)并注册到选择器(Selector)

    • 服务器创建一个ServerSocketChannel并绑定端口,等待客户端连接。
    • ServerSocketChannel设置为非阻塞模式,并注册到Selector,表示服务器现在开始通过Selector管理该通道。
  2. 选择器轮询事件

    • 服务器主线程调用Selector.select()方法。这是一个阻塞方法,但它会在有事件发生时返回,例如某个Channel有新数据可读、可写,或有新连接到达。
    • 一旦有事件触发,Selector会返回这些事件的集合,服务器线程可以根据这些事件选择性地处理相应的通道。
  3. 处理事件(如读取或写入)

    • 假设一个通道上有数据可读,服务器线程会读取数据并将它放入缓冲区,进行相应的业务逻辑处理。
    • 读取完成后,线程可以继续检查其他通道的状态,不必在一个连接上等待。
  4. 结束或继续等待

    • 如果客户端关闭连接,服务器会注销该通道;否则,线程继续通过Selector等待新事件。

2.4 NIO的优缺点分析

优点

  • 高效的资源利用:一个线程可管理多个连接,不需要为每个连接创建一个线程,大大降低了线程的数量和资源消耗。

  • 适合高并发:NIO更适合需要处理大量连接的场景,比如聊天室、实时系统等。

缺点

  • 实现复杂:NIO的代码实现比BIO复杂,理解通道、缓冲区、选择器的机制需要更多经验。

  • 适用性有限:NIO适用于长连接场景(如聊天室),但对于短连接或低并发场景,BIO可能更简单易用。

2.5 NIO的应用实例——Netty

        Netty 是一个基于 NIO 的高性能网络应用框架,专门为了解决 Java 网络编程中的复杂性和性能问题。Netty 封装了底层的 NIO 操作,使得编写高并发、可扩展的网络应用更加轻松。它通常用于开发高性能的网络服务器和客户端,尤其在分布式系统、微服务等需要处理大量连接的场景中非常流行。

1. Netty 的核心概念

        Netty 主要使用 NIO 的非阻塞特性,并在其基础上进一步封装和优化,核心组件包括EventLoopChannelPipelineHandler 等。我们来详细看看这些核心部分:

  1. Channel

    • Netty 中的 Channel 是数据读写的基本接口,表示网络连接的抽象。不同的 Channel 实现支持不同协议(如 TCP、UDP),每个 Channel 可以绑定不同的事件。
  2. EventLoop

    • Netty 使用 EventLoop 来管理和调度 Channel 上的事件。EventLoop 是一个事件循环,用于处理 I/O 操作和事件分发。通常,一个 EventLoop 可以管理多个 Channel,从而实现高效的多路复用。
  3. Pipeline 和 Handler

    • Pipeline 是 Netty 中的一个职责链,所有的事件和数据都会沿着这条链进行传输和处理。
    • Handler 则是 Pipeline 中的处理单元,每个 Handler 负责处理某一种类型的事件,比如读取数据、解码、业务处理等。
    • Pipeline 中的 Handler 可以分为“入站(Inbound)”和“出站(Outbound)”,分别用于处理输入数据和输出数据,整个数据流的处理通过 Pipeline 完成。

2. Netty 的工作流程

Netty 的工作流程比直接使用 NIO 更加简洁,以下是 Netty 服务器的一般流程:

  1. 启动引导程序:创建一个 ServerBootstrap 实例,用于配置和启动服务器。ServerBootstrap 允许我们设置 EventLoop 线程池、Channel 类型以及其他参数。

  2. 初始化 Channel 和 Pipeline

    • ServerBootstrap 中配置 Channel 的类型(比如 NioServerSocketChannel 表示使用 NIO)。
    • Channel 配置 Pipeline,并将业务逻辑的 Handler 加入到 Pipeline 中,Netty 会根据事件触发不同的 Handler
  3. 处理连接和数据

    • 当有客户端连接到服务器时,Netty 会自动创建一个 Channel 来处理该连接,并触发相应的事件。
    • 数据从客户端到达后会按顺序通过 Pipeline 中的每个 Handler,经过编码、解码、业务处理等过程,最后将响应返回客户端。

3. Netty 的优势

        Netty 在底层优化了 Java NIO 的性能,同时提供了开发者友好的接口,简化了许多 NIO 编程的复杂性。

  • 高并发性:Netty 的 EventLoop 模型和 NIO 非阻塞特性,使得它可以高效处理大量并发连接。

  • 易于扩展:Netty 的 PipelineHandler 机制让网络应用的开发和扩展变得灵活。可以随时在 Pipeline 中添加、移除、替换处理逻辑。

  • 丰富的功能支持:Netty 不仅支持 TCP、UDP 等常见协议,还提供了 HTTP、WebSocket 等协议的封装,方便构建多种类型的网络应用。

4. Netty 的核心组件深入分析

  1. EventLoopGroup 和多线程模型

    • Netty 的 EventLoopGroup 是一种线程管理机制,它的作用是管理 EventLoop,并负责调度所有的 I/O 事件和任务。通常,一个 EventLoopGroup 会分配多个线程,每个线程负责管理一个或多个 Channel,从而实现高效的并发处理。
    • 通常在服务端会使用两个 EventLoopGroup,一个用于接收新连接(Boss Group),另一个用于处理数据读写(Worker Group)。这使得 Netty 能够分离连接建立与数据处理的任务,避免资源争用。
  2. Channel 和 ChannelFuture

    • Channel 作为 I/O 操作的核心接口,支持异步操作。每个操作都会返回一个 ChannelFuture 对象,用于监听操作的完成状态,比如连接是否成功、数据是否发送完毕等。
    • ChannelFuture 提供回调机制,允许我们在操作完成后触发相应的处理逻辑。这种异步操作方式让 Netty 能够更高效地进行并发处理。
  3. ChannelHandler 和 Pipeline

    • ChannelHandler 是 Netty 的处理单元,用于对 I/O 事件进行处理。通过 Pipeline,可以将多个 Handler 组成一个处理链条。Pipeline 会根据事件类型(比如读取、写入)将事件依次传递给链条中的 Handler
    • Pipeline 中的 Handler 分为入站和出站两种,入站 Handler 负责处理从客户端来的请求数据,而出站 Handler 则处理响应数据。这样可以实现数据的灵活处理和清晰的逻辑分离。
  4. ByteBuf 缓冲区

    • Netty 提供了 ByteBuf 作为数据缓冲区替代 NIOByteBufferByteBuf 的功能更丰富,比如动态扩展、读写指针分离等,极大地简化了数据处理过程。

5. Netty 常见的使用场景

Netty 的高性能和灵活性使它在许多应用场景中表现出色,以下是一些常见的场景:

  1. 实时聊天系统

    • 由于聊天系统需要支持大量长连接,且需要实时响应消息,Netty 的高并发处理能力非常适合这种场景。通过 Pipeline 可以实现数据的快速传递和处理,保证消息的快速响应。
  2. 微服务间通信

    • 在微服务架构中,服务之间的通信通常是通过网络完成的。Netty 支持多种协议,并能够封装成适合服务间通信的自定义协议(例如基于 TCP 的协议)。Netty 的高效 I/O 模型可以减少通信延迟,适合服务间的大量数据传输。
  3. 游戏服务器

    • 在线游戏需要支持大量玩家的连接,同时对实时性要求高。Netty 可以用于游戏服务器的底层网络架构,利用 NIO 模型减少连接管理的资源消耗,并提供快速响应。
  4. 分布式系统中作为 RPC 框架

    • Netty 是许多 RPC 框架的底层通信支持。比如 DubbogRPC 等分布式系统中常用的框架都使用 Netty 来处理底层网络通信。通过 Netty,能够实现低延迟的远程调用。

6. Netty 示例:构建一个简单的 Echo 服务器

        为了加深理解,我们来看一个 Netty 示例:一个简单的 Echo 服务器。Echo 服务器会将客户端发送的数据原封不动地返回给客户端。

public class EchoServer {public static void main(String[] args) throws Exception {EventLoopGroup bossGroup = new NioEventLoopGroup(1); // 用于接收连接EventLoopGroup workerGroup = new NioEventLoopGroup(); // 用于处理数据try {ServerBootstrap b = new ServerBootstrap(); // 创建引导程序b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) // 使用NIO.childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ch.pipeline().addLast(new EchoServerHandler()); // 加入Echo处理器}});ChannelFuture f = b.bind(8080).sync(); // 绑定端口并启动f.channel().closeFuture().sync(); // 等待关闭} finally {bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}
}class EchoServerHandler extends ChannelInboundHandlerAdapter {@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) {ctx.write(msg); // 写回收到的数据ctx.flush(); // 立即发送}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {cause.printStackTrace();ctx.close(); // 发生异常时关闭通道}
}

这个代码展示了 Netty 的基本工作流程:

  • ServerBootstrap 设置服务器的基本配置。
  • EventLoopGroup 负责处理连接和数据。
  • ChannelInitializer 配置了 Pipeline,将处理器加入到处理链中。
  • EchoServerHandlerchannelRead 中接收数据并返回给客户端。

3. AIO(Asynchronous I/O)

        AIO 模型是在 Java 7 中引入的,也被称为 NIO.2,它与 BIO 和 NIO 的关键不同点在于完全异步的处理方式。AIO 允许我们在 I/O 操作完成后自动调用回调函数,不需要通过轮询或等待的方式来检查 I/O 是否已完成,这种特性在处理长时间的、数据密集型的任务时特别有优势。

3.1 AIO 的关键特性

  1. 异步非阻塞

    • 在 AIO 模型中,操作是非阻塞且异步的。无论是连接、读取还是写入操作,都会直接返回,通过回调机制在操作完成后通知应用进行相应的处理。线程无需等待数据读写完成,能够更高效地处理其他任务。
  2. 基于回调的编程方式

    • AIO 通过回调机制实现异步处理。每当 I/O 操作完成后,系统会自动调用指定的回调方法,这样线程无需手动轮询操作状态。回调机制使得程序结构更加简洁,减少了阻塞等待和轮询操作。

3.2 AIO 的核心组件

        在 AIO 中,核心组件围绕 AsynchronousChannel 系列接口设计,这些接口提供了异步 I/O 的主要操作。

  1. AsynchronousServerSocketChannel

    • 用于异步地处理服务器端的连接请求。它类似于 NIO 中的 ServerSocketChannel,但它提供了异步的 accept 操作,支持在新连接到达时自动触发回调。
  2. AsynchronousSocketChannel

    • 用于客户端或服务器端进行异步数据传输的通道。AsynchronousSocketChannel 提供了异步的读写操作,操作完成后会触发回调。
  3. CompletionHandler

    • 这是 AIO 处理中最重要的接口之一。CompletionHandler 负责定义回调逻辑,在 I/O 操作完成或失败后会自动调用。CompletionHandler 接口包含两个方法:
      • completed:在 I/O 操作成功时调用,处理成功逻辑。
      • failed:在 I/O 操作失败时调用,处理异常逻辑。

3.3 AIO 的工作流程

        AIO 的工作流程基于回调,我们可以用步骤来概述其操作:

  1. 建立连接

    • 使用 AsynchronousServerSocketChannel 监听客户端连接,通过 accept 方法注册一个回调 CompletionHandler。当有新的连接请求时,回调函数会被触发,服务器会获取该连接的 AsynchronousSocketChannel 进行后续的处理。
  2. 异步读取

    • 在服务器获取到客户端连接的 AsynchronousSocketChannel 后,可以调用 read 方法进行数据读取。此方法也是异步的,接收一个 CompletionHandler 作为参数,数据读取完成后将自动触发回调处理。
  3. 异步写入

    • 数据处理完毕后,可以调用 write 方法将结果返回给客户端,同样也是异步的。写入完成后会触发相应的回调,保证了数据的准确发送。

3.4 AIO 的优缺点

优点

  • 完全异步:AIO 的回调机制减少了阻塞等待,提高了程序的响应速度。
  • 资源节约:不需要多线程来管理 I/O,可以在较少线程下完成高并发的 I/O 操作,特别适合高并发的长连接场景。

缺点

  • 复杂性增加:AIO 的回调编程方式需要设计异步流程,逻辑上会比传统的同步代码复杂。
  • 适用场景有限:AIO 适用于高并发、长时间保持连接的应用场景(如文件传输服务器),但在短连接或低并发情况下不具备明显优势。

3.5 AIO 示例:构建一个简单的 Echo 服务器

        以下是一个使用 AIO 的简单 Echo 服务器示例。该服务器会异步接收客户端的数据并返回。

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;public class AioEchoServer {public static void main(String[] args) throws IOException {AsynchronousServerSocketChannel serverChannel =AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(8080));System.out.println("AIO Echo Server is listening on port 8080...");// 接收客户端连接serverChannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() {@Overridepublic void completed(AsynchronousSocketChannel clientChannel, Void attachment) {// 继续接收其他连接serverChannel.accept(null, this);// 读取客户端数据ByteBuffer buffer = ByteBuffer.allocate(1024);clientChannel.read(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() {@Overridepublic void completed(Integer result, ByteBuffer attachment) {attachment.flip();clientChannel.write(attachment, attachment, new CompletionHandler<Integer, ByteBuffer>() {@Overridepublic void completed(Integer result, ByteBuffer attachment) {attachment.clear();clientChannel.read(attachment, attachment, this);}@Overridepublic void failed(Throwable exc, ByteBuffer attachment) {exc.printStackTrace();try {clientChannel.close();} catch (IOException e) {e.printStackTrace();}}});}@Overridepublic void failed(Throwable exc, ByteBuffer attachment) {exc.printStackTrace();try {clientChannel.close();} catch (IOException e) {e.printStackTrace();}}});}@Overridepublic void failed(Throwable exc, Void attachment) {exc.printStackTrace();}});// 阻止主线程退出try {Thread.currentThread().join();} catch (InterruptedException e) {e.printStackTrace();}}
}

总结

  • BIO:每个连接一个线程,适用于低并发、小规模应用。
  • NIO:多路复用、非阻塞,适合高并发场景。
  • AIO:完全异步,回调机制适合高并发、长连接场景。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/60001.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C#】使用.net9在C#中向现有对象动态添加属性

在 C# 中向现有对象动态添加属性并不像在 Python 或 JavaScript 中那样容易&#xff0c;因为 C# 是一种强类型语言。 但是&#xff0c;我们可以通过使用一些技术和库来实现这一点&#xff0c;例如扩展方法、字典等。本文将详细介绍如何在 C# 中实现这一点。ExpandoObject 方法 …

Python学习从0到1 day26 第三阶段 Spark ⑤ 搜索引擎日志分析

目录 一、搜索引擎日志分析 二、需求1&#xff1a;热门搜索时间段(小时精度)Top3 实现步骤 三、需求2&#xff1a;打印输出:热门搜索词Top3 实现步骤 四、需求3&#xff1a;打印输出:统计hadoop关键字在哪个时段被搜索最多 实现步骤 五、需求4&#xff1a;将数据转换为JSON格式…

#渗透测试#SRC漏洞挖掘#深入挖掘CSRF漏洞01

免责声明 本教程仅为合法的教学目的而准备&#xff0c;严禁用于任何形式的违法犯罪活动及其他商业行为&#xff0c;在使用本教程前&#xff0c;您应确保该行为符合当地的法律法规&#xff0c;继续阅读即表示您需自行承担所有操作的后果&#xff0c;如有异议&#xff0c;请立即停…

揭秘云计算 | 2、业务需求推动IT发展

揭秘云计算 | 1、云从哪里来&#xff1f;-CSDN博客https://blog.csdn.net/Ultipa/article/details/143430941?spm1001.2014.3001.5502 书接上文&#xff1a; 过去几十年间IT行业从大型主机过渡到客户端/服务器&#xff0c;再过渡到现如今的万物互联&#xff0c;IT可把控的资…

Grover算法——量子搜索算法

假设N个数据中符合条件的数据有M个&#xff0c;则量子搜索算法的复杂度为&#xff0c;远小于经典算法的复杂度。 黑箱 下面以N2为例&#xff0c;介绍黑箱如何标记符合条件的数据。N2意味着只有两个数据&#xff0c;可以用0和1来表示这两个数据&#xff0c;也就只需要一个量子比…

Ubuntu24.04网络异常与应对方案记录

PS: 参加过408改卷的ZJU ghsongzju.edu.cn 开启嘲讽: 你们知道408有多简单吗&#xff0c;操作系统真实水平自己知道就行&#xff5e;&#xff5e; Requested credits of master in UWSC30&#xff0c;in ZJU24&#xff0c;domestic master is too simple ubuntu安全软件 在 U…

智能的编织:C++中auto的编织艺术

在C的世界里&#xff0c;auto这个关键字就像是一个聪明的助手&#xff0c;它能够自动帮你识别变量的类型&#xff0c;让你的代码更加简洁和清晰。下面&#xff0c;我们就来聊聊auto这个关键字的前世今生&#xff0c;以及它在C11标准中的新用法。 auto的前世 在C11之前&#x…

Spark的Standalone集群环境安装

一.简介 与MR对比&#xff1a; 概念MRYARNSpark Standalone主节点ResourceManagerMaster从节点NodeManagerWorker计算进程MapTask&#xff0c;ReduceTaskExecutor 架构&#xff1a;普通分布式主从架构 主&#xff1a;Master&#xff1a;管理节点&#xff1a;管理从节点、接…

cache(一)基本概念

在知乎发现一份不错得学习资料 请教CPU的cache中关于line,block,index等的理解&#xff1f; PPT 地址 https%3A//cs.slu.edu/%7Efritts/CSCI224_S15/schedule/chap6-cache-memory.pptx 课程主页 https://cs.slu.edu/~fritts/CSCI224_S15/schedule/ 文章目录 1. cache概念2. cac…

前端CSS3 渐变详解

文章目录 CSS3 渐变详解一、引言二、CSS3 渐变基础1、线性渐变1.1、基本线性渐变1.2、改变渐变方向 2、径向渐变2.1、基本径向渐变2.2、设置径向渐变的中心 三、高级渐变技巧1、重复渐变1.1、重复线性渐变1.2、重复径向渐变 四、总结 CSS3 渐变详解 一、引言 在现代网页设计中…

ubuntu下aarch64-linux-gnu(交叉编译) gdb/gdbserver(二)

ubuntu下aarch64-linux-gnu(交叉编译) gdb/gdbserver&#xff08;二&#xff09; 本教程作为gdb/gdbserver编译安装教程的一个补充&#xff0c;教会大家如何使用gdb/gdbserver进行远程调试。 如上图所示&#xff0c;我们需要将编译后的gdbserver上传至目标设备&#xff0c;其上…

(65)使用RLS自适应滤波器进行信道均衡的MATLAB仿真

文章目录 前言一、仿真说明二、码间串扰、色散、与频率选择性衰落1. 码间串扰&#xff08;ISI&#xff09;2. 信道的色散与码间串扰3. 减少ISI的方法 三、MATLAB仿真代码四、仿真结果1.发送16QAM信号的星座图2.信道的频率响应3.接收16QAM信号的星座图4.均衡后16QAM信号的星座图…

【数据分析】如何构建指标体系?

有哪些指标体系搭建模型&#xff1f;五个步骤教你从0开始搭建指标体系 一、企业指标体系搭建存在什么问题 许多企业在搭建数据指标体系时遇到了诸多难题&#xff0c;如问题定位不准确、数据采集不完整、目标不一致、报表无序、指标覆盖不全面以及报表价值未充分利用等。 1、…

【Linux 30】传输层协议 - TCP

文章目录 &#x1f308; 一、TCP 协议介绍⭐ 1. TCP 协议的特点 &#x1f308; 二、TCP 协议格式⭐ 1. TCP 报头中各字段的含义⭐ 2. 各 TCP 标志位的用途⭐ 3. 使用结构体描述 TCP 报头 &#x1f308; 三、TCP 的窗口⭐ 1. TCP 的发送和接收缓冲区⭐ 2. TCP 为什么存在缓冲区⭐…

【Linux杂货铺】IO多路复用

目录 &#x1f308;前言&#x1f308; &#x1f4c1; 五种IO模型 &#x1f4c2; 阻塞IO &#x1f4c2; 非阻塞IO &#x1f4c2; 信号驱动IO &#x1f4c2; 多路复用 &#x1f4c2; 异步IO &#x1f4c1; 非阻塞IO实现 &#x1f4c1; select &#x1f4c2; 接口使用 &#x…

Kafka 的一些问题,夺命15连问

kafka-中的组成员 kafka四大核心 生产者API 允许应用程序发布记录流至一个或者多个kafka的主题&#xff08;topics&#xff09;。 消费者API 允许应用程序订阅一个或者多个主题&#xff0c;并处理这些主题接收到的记录流 StreamsAPI 允许应用程序充当流处理器&#xff08;s…

ANNOVAR下载

1.官网 https://annovar.openbioinformatics.org/en/latest/user-guide/startup/ 都填英文 要不然会报错 tar -xzvf annovar.latest.tar.gztree . ├── annotate_variation.pl ├── coding_change.pl ├── convert2annovar.pl ├── example │ ├── ex1.avinput…

集群架构中Lua脚本的限制以及出现的报错

&#x1f680; 博主介绍&#xff1a;大家好&#xff0c;我是无休居士&#xff01;一枚任职于一线Top3互联网大厂的Java开发工程师&#xff01; &#x1f680; &#x1f31f; 在这里&#xff0c;你将找到通往Java技术大门的钥匙。作为一个爱敲代码技术人&#xff0c;我不仅热衷…

大语言模型:解锁自然语言处理的无限可能

0.引言 在当今的科技时代&#xff0c;自然语言处理技术正以前所未有的速度发展&#xff0c;语言大模型作为其中的核心力量&#xff0c;对各个领域产生了深远的影响。本文旨在探讨语言大模型的发展历程、核心技术以及广泛的应用场景&#xff0c;以帮助读者更好地理解这一前沿技…

MATLAB实现智能水滴算法(Intelligent Water Drops Algorithm, IWDA)

1.智能水滴算法介绍 智能水滴算法&#xff08;Intelligent Water Drops Algorithm&#xff0c;IWDA&#xff09;是一种基于水滴特性的智能优化算法&#xff0c;它借鉴了水滴在自然界中的运动和形态变化规律&#xff0c;通过模拟水滴的形成、发展和消亡过程&#xff0c;实现问题…