Redis IO多路复用
0、前言
本文所有代码可见 => 【gitee code demo】
本文涉及的主题:
1、BIO、NIO的业务实践和缺陷
2、Redis IO多路复用:redis快的主要原因
3、epoll 架构
部分图片 via 【epoll 原理分析】
1、BIO单线程版
1.1 业务代码
client client代码相同 启动多个即可
public class RedisClient1 {public static void main(String[] args) throws IOException {SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");Socket socket = new Socket("127.0.0.1", 6300);log("{} {}> 尝试连接服务 {}", sdf.format(new Date()) ,socket.getLocalPort(), socket.getPort());OutputStream outputStream = socket.getOutputStream();while (true) {Scanner scanner = new Scanner(System.in);log("{} {}> ", sdf.format(new Date()) ,socket.getLocalPort());String string = scanner.nextLine();if (string.equalsIgnoreCase("quit")) {break;}socket.getOutputStream().write(string.getBytes());log("{} {}> 发送数据:{}", sdf.format(new Date()) ,socket.getLocalPort(), string);}outputStream.close();socket.close();}}
server
public class RedisServerBIO {public static void main(String[] args) throws IOException {SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");ServerSocket serverSocket = new ServerSocket(6300);while (true) {log("{} {}> ", sdf.format(new Date()), serverSocket.getLocalPort());Socket socket = serverSocket.accept();//阻塞1 ,等待客户端连接log("{} {}> {} 连接到服务", sdf.format(new Date()), socket.getLocalPort(), socket.getPort());InputStream inputStream = socket.getInputStream();int length = -1;byte[] bytes = new byte[1024];log("{} {}> ", sdf.format(new Date()), serverSocket.getLocalPort());while ((length = inputStream.read(bytes)) != -1)//阻塞2 ,等待客户端发送数据{log("{} {}> 收到 {} 的消息:{}", sdf.format(new Date()), serverSocket.getLocalPort(), socket.getPort(), new String(bytes, 0, length));}inputStream.close();socket.close();}}
}
1.2 结果演示
现象:
1、client1 连接到server,client2尝试连接被阻塞
2、client2 先发送的消息未被server接受,client1后发送的repeat消息被server接受
结论:
BIO会一直阻塞,单线程下只能处理一个socket连接
存在的问题:
多 client 访问时效率低

2、BIO多线程版
2.1 业务代码
public class RedisServerBIOMultiThread {public static void main(String[] args) throws IOException {ServerSocket serverSocket = new ServerSocket(6300);SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");log("{} {}> ", sdf.format(new Date()), serverSocket.getLocalPort());while (true) {Socket socket = serverSocket.accept();//阻塞1 ,等待客户端连接log("{} {}> {} 连接到服务", sdf.format(new Date()), socket.getLocalPort(), socket.getPort());new Thread(() -> {try {InputStream inputStream = socket.getInputStream();int length = -1;byte[] bytes = new byte[1024];while ((length = inputStream.read(bytes)) != -1)//阻塞2 ,等待客户端发送数据{log("{} {}> 收到 {} 的消息:{}", sdf.format(new Date()), serverSocket.getLocalPort(), socket.getPort(), new String(bytes, 0, length));}inputStream.close();socket.close();} catch (IOException e) {e.printStackTrace();}}, Thread.currentThread().getName()).start();System.out.println(Thread.currentThread().getName());}}
}
2.1 结果演示
现象:
client1 、client2 都能正常连接到 server且正常发送、接受消息
结论:
BIO多线程提高处理能力,可以同时处理多个socket连接
存在的问题:
每个线程只能处理一个socket,当client数量大时,需要消耗大量线程资源

3、NIO
3.1 业务代码
当一个客户端与服务端进行连接,这个socket就会加入到一个容器中,隔一段时间遍历一次,看这个socket的read()方法能否读到数据,这样一个线程就能处理多个客户端的连接和读取了
public class RedisServerNIO {static ArrayList<SocketChannel> socketList = new ArrayList<>();static ByteBuffer byteBuffer = ByteBuffer.allocate(1024);public static void main(String[] args) throws IOException {ServerSocketChannel serverSocket = ServerSocketChannel.open();SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");serverSocket.bind(new InetSocketAddress("127.0.0.1", 6300));serverSocket.configureBlocking(false);//设置为非阻塞模式while (true) {for (SocketChannel element : socketList) {int read = element.read(byteBuffer);if (read > 0) {byteBuffer.flip();byte[] bytes = new byte[read];byteBuffer.get(bytes);//System.out.println(JSONUtil.toJsonStr(element));log("{} {}> 收到 {} 的消息:{}", sdf.format(new Date()), element.socket().getLocalPort(), element.socket().getPort(), new String(bytes, 0, read));byteBuffer.clear(); }}SocketChannel socketChannel = serverSocket.accept();if (socketChannel != null) {log("{} {}> {} 连接到服务", sdf.format(new Date()), socketChannel.socket().getLocalPort(), socketChannel.socket().getPort());socketChannel.configureBlocking(false);//设置为非阻塞模式socketList.add(socketChannel);log("{} {}> socket 数量: {} ", sdf.format(new Date()), socketChannel.socket().getLocalPort(), socketList.size());}}}
}
3.2 结果演示
现象:
1、client1 、client2 都能正常连接到 server且正常发送、接受消息
2、server 没有创建额外线程
结论:
NIO 可以实现一个线程处理多个 socket 连接
存在的问题:
1、每次遍历所有socket,有很多无用功
2、遍历过程在用户态,还需要将数据从内核态读取到用户态

4、IO多路复用
1、使用 epoll() 实现,多个网络连接 socket 复用同一个线程
2、基于事件驱动机制,socket 中有数据会主动通知内核,并加入到就绪链表中,不需要遍历所有 socket
3、减少了内核态和用户态的切换
Redis IO多路复用实现

4.1 epoll_create()
创建内核中的fd容器

4.2 epoll_ctl()
epoll_ctl函数用于增加,删除,修改epoll事件,epoll事件会存储于内核epoll结构体红黑树中

4.3 epoll_wait
用于监听套接字事件,可以通过设置超时时间timeout来控制监听的行为为阻塞模式还是超时模式

4.4 epoll 软件架构

相关文章:
Redis IO多路复用
0、前言 本文所有代码可见 > 【gitee code demo】 本文涉及的主题: 1、BIO、NIO的业务实践和缺陷 2、Redis IO多路复用:redis快的主要原因 3、epoll 架构 部分图片 via 【epoll 原理分析】 1、BIO单线程版 1.1 业务代码 client client代码相同…...
如何在Vue中实现拖拽功能?
Vue.js是一款流行的JavaScript框架,用于构建用户界面。其中一个常见的需求是在Vue中实现拖拽功能,让用户可以通过拖拽元素来进行交互。今天,我们就来学习如何在Vue中实现这一功能。 首先,我们需要明白拖拽功能的基本原理…...
在Linux下使用Docker部署chirpstack
目录 一、前言 二、chirpstack 1、chirpstack是什么 2、chirpstack组件 3、为什么选择Docker部署 三、Linux下部署过程 四、web界面部署过程 一、前言 本篇文章我是在Linux下使用 Docker 进行部署chirpstack,chirpstack采用的是v4 版本,v4 版本 与…...
《昇思25天学习打卡营第14天|计算机视觉-ShuffleNet图像分类》
FCN图像语义分割&ResNet50迁移学习&ResNet50图像分类 当前案例不支持在GPU设备上静态图模式运行,其他模式运行皆支持。 ShuffleNet网络介绍 ShuffleNetV1是旷视科技提出的一种计算高效的CNN模型,和MobileNet, SqueezeNet等一样主要应用在移动端…...
将字符串写入结构体变量中
将字符串写入结构体变量中,主要涉及到结构体中字符数组(或指针)的使用。 一、使用字符数组 假设你有一个结构体,它包含一个字符数组来存储字符串: #include <stdio.h> #include <string.h> // 用于st…...
iPhone 16 Pro系列将标配潜望镜头:已开始生产,支持5倍变焦
ChatGPT狂飙160天,世界已经不是之前的样子。 更多资源欢迎关注 7月6日消息,据DigiTimes最新报道,苹果将在iPhone 16 Pro中引入iPhone 15 Pro Max同款5倍光学变焦四棱镜潜望镜头。 报道称,目前苹果已经将模组订单交至大立光电和玉…...
PG在还没有pg_class的时候怎么访问基础系统表?
在没有pg_class的时候,数据库怎么访问系统表?这个问题可以分成两个阶段来看: 数据库簇初始化,此时一个database都没有,所以怎么构造和访问pg_class等系统表是一个问题私有内存初始化系统表。PG的系统表信息是放在back…...
UnityHub 无法添加模块问题
文章目录 1.问题描述2.问题解决 1.问题描述 在Hub中无法添加模块 2.问题解决 1、点击设置 2、设置版本安装位置 可以发现installs的安装位置路径设置不是unity安装位置,这里我们更改成自己电脑unity安装位置的上一级路径 添加模块正常:...
python04——类(基础new)
类其实也是一种封装的思想,类就是把变量、方法等封装在一起,然后可以通过不同的实例化对其进行调用操作。 1.类的定义 class 类名: 变量a def __init__ (self,参数2,参数2...):初始化函数!!&…...
【Python百日进阶-Web开发-Peewee】Day296 - 查询示例(五)聚合2、递归
文章目录 14.6.13 列出每个指定设施的预订总小时数 List the total hours booked per named facility14.6.14 列出每位会员在 2012 年 9 月 1 日之后的首次预订 List each member’s first booking after September 1st 201214.6.15 生成成员名称列表,每行包含成员总数 Produc…...
闲话银行家舍入法,以及在程序中如何实现
前言 相信对于四舍五入的舍入法,大家都耳熟能详,但对于银行家舍入法,可能就会比较少接触了! 可是在金融界,银行家舍入法可是大名鼎鼎的主角之一,主要应用于金融领域和涉及货币计算的场合。 那么…...
最短路径算法(算法篇)
算法之最短路径算法 最短路径算法 概念: 考查最短路径问题,可能会输入一个赋权图(也就是边带有权的图),则一条路径的v1v2…vN的值就是对路径的边的权求和,这叫做赋权路径长,如果是无权路径长就是单纯的路径上的边数。…...
昇思25天学习打卡营第11天 | LLM原理和实践:基于MindSpore实现BERT对话情绪识别
1. 基于MindSpore实现BERT对话情绪识别 1.1 环境配置 # 实验环境已经预装了mindspore2.2.14,如需更换mindspore版本,可更改下面mindspore的版本号 !pip uninstall mindspore -y !pip install -i https://pypi.mirrors.ustc.edu.cn/simple mindspore2.2…...
反向散射技术(backscatter communication)
智能反射表面辅助的反向散射通信系统研究综述(知网) 1 反向散射通信技术优势和应用场景 反向散射通信技术通过被动射频技术发送信号,不需要一定配有主动射频单元,被认为是构建绿色节能、低成本、可灵活部署的未来物联网规模化应用关键技术之一,是实现“…...
致远CopyFile文件复制漏洞
复现版本 V8.0SP2 漏洞范围 V5&G6_V6.1至V8.0SP2全系列版本、V5&G6&N_V8.1至V8.1SP2全系列版本。 漏洞复现 上传文件 POST /seeyon/ajax.do?methodajaxAction&managerNameportalCssManager&rnd57507 HTTP/1.1 Accept: */* Content-Type: applicatio…...
MySQL 创建数据库
MySQL 创建数据库 在当今的数据驱动世界中,数据库是任何应用程序的核心组成部分。MySQL,作为一个流行的开源关系数据库管理系统,因其可靠性、易用性和强大的功能而广受欢迎。本文将详细介绍如何在MySQL中创建数据库,包括基础知识和最佳实践。 什么是MySQL数据库? MySQL…...
AbyssFish单连通周期边界多孔结构2D软件
软件介绍 AbyssFish单连通周期边界多孔结构2D软件(以下简称软件)可用于生成具备周期性边界条件的单连通域多孔结构PNG图片,软件可设置生成模型的尺寸、孔隙率、孔隙尺寸、孔喉尺寸等参数,并且具备孔隙形态控制功能。 软件生成的…...
Linux驱动开发-03字符设备驱动框架搭建
一、字符设备驱动开发步骤 驱动模块的加载和卸载(将驱动编译模块,insmod加载驱动运行)字符设备注册与注销(我们的驱动实际上是去操作底层的硬件,所以需要向系统注册一个设备,告诉Linux系统,我有…...
Zynq系列FPGA实现SDI视频编解码+图像缩放+多路视频拼接,基于GTX高速接口,提供8套工程源码和技术支持
目录 1、前言工程概述免责声明 2、相关方案推荐本博已有的 SDI 编解码方案本博已有的FPGA图像缩放方案本方案的无缩放应用本方案在Xilinx--Kintex系列FPGA上的应用 3、详细设计方案设计原理框图SDI 输入设备Gv8601a 均衡器GTX 解串与串化SMPTE SD/HD/3G SDI IP核BT1120转RGB自研…...
VS2019使用C#写窗体程序技巧(1)
1、打开串口 private void button1_Click(object sender, EventArgs e){myPort cmb1.Text;mybaud Convert.ToInt32(cmb2.Text, 10);databit 8;parity Parity.None;stopBit StopBits.One;textBox9.Text "2";try{sp new SerialPort(myPort, mybaud, parity, dat…...
应用升级/灾备测试时使用guarantee 闪回点迅速回退
1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...
Spark 之 入门讲解详细版(1)
1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室(Algorithms, Machines, and People Lab)开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目,8个月后成为Apache顶级项目,速度之快足见过人之处&…...
将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?
Otsu 是一种自动阈值化方法,用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理,能够自动确定一个阈值,将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...
Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...
华为OD机试-食堂供餐-二分法
import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...
有限自动机到正规文法转换器v1.0
1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...
docker 部署发现spring.profiles.active 问题
报错: org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...
Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...
【分享】推荐一些办公小工具
1、PDF 在线转换 https://smallpdf.com/cn/pdf-tools 推荐理由:大部分的转换软件需要收费,要么功能不齐全,而开会员又用不了几次浪费钱,借用别人的又不安全。 这个网站它不需要登录或下载安装。而且提供的免费功能就能满足日常…...
push [特殊字符] present
push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...
