什么是I/O?

I/O

什么是I/O?

I/O即输入(Input)输出(Output)

从计算机结构角度来看:

计算机有输入设备(键盘等)和输出设备(显示屏等),(网卡和硬盘既可以作为输入也可以作为输出)。

所以从计算机结构角度来看,I/O描述的是计算机系统与外部系统的通信

从应用程序角度来看:

为了保证操作系统的安全性和稳定性,一个进程的地址空间被分为用户空间内核空间

我们平时的应用程序都是运行在用户空间,而像文件管理、进程通信、内存管理、I/O等都是需要依赖内核空间来完成的。

而我们要执行I/O操作时,由于我们没有权限,所以只有发起系统调用,让操作系统来帮我们完成。而我们一般开发常见的就是磁盘I/O(读写文件)和网络I/O(网络请求和响应)

所以从应用程序来看,I/O是指我们的应用程序对操作系统内核发起I/O调用(系统调用)操作系统来负责具体的I/O,将我们需要的数据从内核空间拷贝到用户空间。

常见的I/O模型

UNIX系统下的五种I/O模型

  • 同步阻塞I/O
  • 同步非阻塞I/O
  • I/O多路复用
  • 信号驱动I/O
  • 异步I/O

Java中3种常见I/O模型

BIO(Blocking I/O)

同步阻塞I/O

BIO在应用程序发起read调用后,会一直进入阻塞,直到系统把数据从内核拷贝到用户空间为止。
在这里插入图片描述

BIO适用与客户端连接数量不多的情况下,如果连接达到十万级甚至百万级,无法适用BIO

NIO(Non-blocking/New I/O)

而Java中的NIO是同步非阻塞I/O还是I/O多路复用呢?

Java中的NIO可以看作I/O多路复用

先看看同步非阻塞I/O
在这里插入图片描述

应用程序会通过轮询的方式反复像内核发起read调用,直到内核把数据拷贝到用户空间。通过轮询虽然避免了阻塞,但是轮询操作十分消耗CPU资源

所以Java选择了I/O多路复用
在这里插入图片描述
首先应用程序会发起一个select调用来询问数据准备好没有,如果准备好了才会发起read调用,通过这种方式减少了无效的系统调用,减少了对CPU的消耗。

NIO中引入了三个重要的概念selectorchannelbuffer;

channel:

  • 读写数据的双向通道

  • 从buffer读入数据,写出数据到buffer

buffer:

  • 缓冲读写数据

selector:

  • 通过一个selector可以管理多个channel,当客户的数据到了之后,才会为其服务。
    在这里插入图片描述

(图中channel拼写错误)

AIO(Asynchronous I/O)

异步非阻塞I/O

AIO的异步是通过事件和回调机制来实现的,应用程序发起调用后会直接返回,不会等待,当后台处理完后,会通知相应的线程继续处理。
在这里插入图片描述

但AIO的应用还并不广泛,具体原因如下

  1. 兼容性:AIO 是在 JDK1.7 中引入的新特性,因此只有使用 JDK1.7 或更高版本的应用程序才能使用 AIO。在实际应用中,许多企业应用程序仍然在使用较老版本的 JDK,因此 AIO 的兼容性是一个问题。
  2. 学习成本:相比于传统的阻塞 I/O 模型和 NIO(非阻塞 I/O)模型,AIO 模型的编程难度更高,需要花费更多的时间和精力学习和理解。这使得一些开发者可能不太愿意采用 AIO。
  3. 稳定性:虽然 AIO 能够提供高吞吐量和低延迟,但在处理高并发请求时,其稳定性可能会降低。而且不同操作系统的实现效果也可能不同,这也是 AIO 应用不广泛的原因之一。
    用 AIO。
  4. 稳定性:虽然 AIO 能够提供高吞吐量和低延迟,但在处理高并发请求时,其稳定性可能会降低。而且不同操作系统的实现效果也可能不同,这也是 AIO 应用不广泛的原因之一。
  5. 应用场景受限:AIO 主要适用于 I/O 密集型应用程序,这也限制了 AIO 应用的范围。对于计算密集型应用程序,AIO 并不一定能够提供更好的性能表现。
这是源代码module SPI_Master #( parameter SPI_MODE = 0, // SPI????0 (CPOL=0, CPHA=0) parameter DATA_WIDTH = 8, // ???????? parameter CLKS_PER_HALF_BIT = 5 // ???????????? )( input wire i_Rst_L, // ???????? (??????) input wire i_Clk, // ???????? // ???????? input wire [DATA_WIDTH-1:0] i_TX_Byte, // ?????????? input wire i_TX_DV, // ???????????? output reg o_TX_Ready, // ?????????? // ???????? output reg o_RX_DV, // ???????????? output reg [DATA_WIDTH-1:0] o_RX_Byte, // ???????? // SPI???????? output wire o_SPI_Clk, // SPI???????? input wire i_SPI_MISO, // ???????? output wire o_SPI_MOSI, // ???????? output wire o_SPI_CS_n // ???? (??????) ); // ?????????? localparam [1:0] IDLE = 2'b00, CS_SETUP = 2'b01, TRANSFER = 2'b10, CS_HOLD = 2'b11; // ?????????????????? localparam BIT_INDEX_WIDTH = $clog2(DATA_WIDTH); // ?????????? reg [1:0] r_SM_CS; // ?????????????? reg [3:0] r_Clk_Count; // ?????????? reg [BIT_INDEX_WIDTH-1:0] r_Bit_Index; // ?????? reg [DATA_WIDTH-1:0] r_TX_Byte; // ?????????????? reg [DATA_WIDTH-1:0] r_RX_Byte; // ?????????????? // ?????????? reg r_o_SPI_Clk; reg r_o_SPI_MOSI; reg r_o_SPI_CS_n; // ?????????? reg r_i_SPI_MISO; // SPI???????? wire w_CPOL = (SPI_MODE == 2) || (SPI_MODE == 3); // ???????? wire w_CPHA = (SPI_MODE == 1) || (SPI_MODE == 3); // ???????? // ???????????????????? localparam [3:0] HALF_BIT_MAX = CLKS_PER_HALF_BIT - 1; localparam [3:0] FULL_BIT_MAX = CLKS_PER_HALF_BIT * 2 - 1; // ???????? always @(posedge i_Clk or negedge i_Rst_L) begin if (~i_Rst_L) begin r_i_SPI_MISO <= 1'b0; end else begin r_i_SPI_MISO <= i_SPI_MISO; end end // ???????????? always @(posedge i_Clk or negedge i_Rst_L) begin if (~i_Rst_L) begin // ?????????????? r_SM_CS <= IDLE; o_TX_Ready <= 1'b1; o_RX_DV <= 1'b0; o_RX_Byte <= 0; r_Clk_Count <= 0; r_Bit_Index <= 0; r_o_SPI_Clk <= w_CPOL; r_o_SPI_MOSI <= 1'b0; r_o_SPI_CS_n <= 1'b1; r_TX_Byte <= 0; r_RX_Byte <= 0; end else begin // ?????? case (r_SM_CS) IDLE: begin o_TX_Ready <= 1'b1; o_RX_DV <= 1'b0; r_o_SPI_Clk <= w_CPOL; if (i_TX_DV) begin o_TX_Ready <= 1'b0; r_TX_Byte <= i_TX_Byte; r_SM_CS <= CS_SETUP; r_Clk_Count <= 0; end end CS_SETUP: begin r_o_SPI_CS_n <= 1'b0; if ($unsigned(r_Clk_Count) < 2) begin r_Clk_Count <= r_Clk_Count + 1; end else begin r_Clk_Count <= 0; r_Bit_Index <= DATA_WIDTH - 1; r_SM_CS <= TRANSFER; end end TRANSFER: begin r_o_SPI_Clk <= (r_Clk_Count < CLKS_PER_HALF_BIT) ? 1'b0 : 1'b1; if ($unsigned(r_Clk_Count) < $unsigned(FULL_BIT_MAX)) begin r_Clk_Count <= r_Clk_Count + 1; end else begin r_Clk_Count <= 0; if (|r_Bit_Index) begin // ?????? r_Bit_Index > 0 r_Bit_Index <= r_Bit_Index - 1; end else begin o_RX_Byte <= r_RX_Byte; o_RX_DV <= 1'b1; r_SM_CS <= CS_HOLD; end end if (r_Clk_Count == HALF_BIT_MAX) begin r_o_SPI_MOSI <= r_TX_Byte[r_Bit_Index]; end if (r_Clk_Count == (HALF_BIT_MAX + CLKS_PER_HALF_BIT)) begin r_RX_Byte[r_Bit_Index] <= r_i_SPI_MISO; end end CS_HOLD: begin o_RX_DV <= 1'b0; r_o_SPI_Clk <= w_CPOL; if ($unsigned(r_Clk_Count) < 2) begin r_Clk_Count <= r_Clk_Count + 1; end else begin r_Clk_Count <= 0; r_o_SPI_CS_n <= 1'b1; o_TX_Ready <= 1'b1; r_SM_CS <= IDLE; end end endcase end end // ???????? assign o_SPI_Clk = r_o_SPI_Clk; assign o_SPI_MOSI = r_o_SPI_MOSI; assign o_SPI_CS_n = r_o_SPI_CS_n; endmodule
07-04
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小C卷Java

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

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

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

打赏作者

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

抵扣说明:

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

余额充值