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 软件架构

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

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

相关文章

Mongodb索引使用限制

学习mongodb&#xff0c;体会mongodb的每一个使用细节&#xff0c;欢迎阅读威赞的文章。这是威赞发布的第85篇mongodb技术文章&#xff0c;欢迎浏览本专栏威赞发布的其他文章。如果您认为我的文章对您有帮助或者解决您的问题&#xff0c;欢迎在文章下面点个赞&#xff0c;或者关…

Sahi+Yolov10

一、前言 了解到Sahi&#xff0c;是通过切图&#xff0c;实现提高小目标的检测效果。sahi 目前支持yolo5\yolo8\mmdet\detection2 等等算法&#xff0c;本篇主要通过实验onnx加载模型的方式使sahi支持yolov10。 二、代码 &#xff08;1&#xff09;转换模型 首先使用 conda创…

大数的排列组合公式C代码

我们知道&#xff0c;计算排列A(n,m)和组合C(n,m)可以用先求阶乘的方式实现&#xff0c;但是当数很大时求阶乘很容易溢出&#xff0c;所以这里给出非阶乘的方式求排列组合 求排列 分母和分子可以抵消&#xff0c;最后代码如下 unsigned long long A(int n, int m) {unsigned…

华为机试HJ34图片整理

华为机试HJ34图片整理 题目&#xff1a; 想法&#xff1a; 将输入的字符串中每个字符都转为ASCII码&#xff0c;再通过快速排序进行排序并输出 input_str input() input_list [int(ord(l)) for l in input_str]def partition(arr, low, high):i low - 1pivot arr[high]f…

RPC与REST

RPC与REST 访问远程服务1远程服务调用&#xff08;Remote Procedure Call&#xff0c;RPC&#xff09;&#xff1a;RPC 解决什么问题&#xff1f;如何解决的&#xff1f;为什么要那样解决&#xff1f;1.1 先解决两个进程间如何交换数据的问题&#xff0c;也就是进程间通信&…

最新扣子(Coze)实战案例:使用扩图功能,让你的图任意变换,完全免费教程

&#x1f9d9;‍♂️ 大家好&#xff0c;我是斜杠君&#xff0c;手把手教你搭建扣子AI应用。 &#x1f4dc; 本教程是《AI应用开发系列教程之扣子(Coze)实战教程》&#xff0c;完全免费学习。 &#x1f440; 微信关注公从号&#xff1a;斜杠君&#xff0c;可获取完整版教程。&a…

如何快速搭建python项目的虚拟环境

itopen组织1、提供OpenHarmony优雅实用的小工具2、手把手适配riscv qemu linux的三方库移植3、未来计划riscv qemu ohos的三方库移植 小程序开发4、一切拥抱开源&#xff0c;拥抱国产化 你在开发python工具的时候还一直使用系统默认的环境吗&#xff1f;是否有遇到有时候…

2024年【北京市安全员-B证】报名考试及北京市安全员-B证最新解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年北京市安全员-B证报名考试为正在备考北京市安全员-B证操作证的学员准备的理论考试专题&#xff0c;每个月更新的北京市安全员-B证最新解析祝您顺利通过北京市安全员-B证考试。 1、【多选题】《中华人民共和国安…

android轮播图入门2——触摸停止与指示器

前言 这次要在上一篇轮播图的基础上做改造&#xff0c;增加两个功能&#xff1a; 用户触摸到轮播图时&#xff0c;停止轮播在轮播图上展示一个小指示器&#xff0c;指示当前轮播组件的位置 触摸停播 触摸停播的设计思路是&#xff1a;监听实现轮播图的触摸事件&#xff0c;…

手把手教你从零开始构建 AI 视频生成模型

在 GitHub 上发现一篇教程&#xff0c;作者详细介绍了如何使用 Python 语言&#xff0c;从零开始构建一个文本到视频生成模型。 涵盖了从理解理论概念到架构编码&#xff0c;最终实现输入文本提示即可生成视频的全过程。 相关链接 GitHub&#xff1a;github.com/FareedKhan-…

python-redis-lock是如何实现锁自动续期的

python-redis-lock简介 python-redis-lock是一个python的第三方库&#xff0c;基于Redis&#xff0c;封装了分布式锁的逻辑&#xff0c;提供了更高级的API来简化锁的获取、保持和释放过程。包括自动续期、锁超时、重入锁等功能。 相比于直接使用redis的setnx&#xff0c;避免了…

倒退型自闭症与轻度自闭症有什么区别?

作为星贝育园自闭症儿童康复中心的一名专业教师&#xff0c;我深知家长们在面对自闭症谱系障碍&#xff08;ASD&#xff09;时的种种疑问与挑战&#xff0c;尤其是关于倒退型自闭症与轻度自闭症之间的区别。今天&#xff0c;我将从专业视角出发&#xff0c;深入浅出地解析这两种…

精通Vim编辑器:Linux系统下的强大文本编辑工具

精通Vim编辑器&#xff1a;Linux系统下的强大文本编辑工具 引言 在Linux世界中&#xff0c;Vim是一个功能强大、高度可定制的文本编辑器&#xff0c;它继承自经典的vi编辑器并提供了一系列增强功能。无论是系统管理员、开发人员还是普通用户&#xff0c;掌握Vim的使用都能大幅…

游戏AI的创造思路-技术基础-强化学习(2)

上一篇中引出了深度强化学习这个大坑&#xff0c;本篇浅浅填一下~~~~ 目录 6. 深度强化学习概述 6.1. 基本概念 6.2. 发展历史 6.3. 基本公式 6.4. Python实现 6.5. 运行原理 6.5.1. 核心要素 6.5.2. 运行原理 6.5.3. 典型算法 6.5.4. Python实现代码 6.6. 优缺点 …

Segmentation fault (core dumped)

错误简介 出现 “Segmentation fault (core dumped)” 错误通常意味着程序访问了未分配的内存或者越界访问了已分配内存之外的区域。 段错误通常发生在以下情况&#xff1a; 空指针解引用&#xff1a;尝试对空指针进行操作。内存越界&#xff1a;访问了超出分配内存边界的区…

大厂面试官赞不绝口的后端技术亮点【后端项目亮点合集(2)】

本文将持续更新~~ hello hello~ &#xff0c;这里是绝命Coding——老白~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f4a5;个人主页&#xff1a;绝命C…

提高论文发表机会:Nature Communications 最新研究教你如何巧妙回复审稿意见

我是娜姐 迪娜学姐 &#xff0c;一个SCI医学期刊编辑&#xff0c;探索用AI工具提效论文写作和发表。 对于科研搬砖人来说&#xff0c;在论文投稿过程中&#xff0c;如何有效回复审稿意见才能得到审稿人的认可&#xff0c;一直是一个让人困惑又带点玄学的问题。 但是&#xff0c…

vue3 按钮复制粘贴功能

1.html <div click"copy(item.envelopePassword)" > 复制口令 </div> 2.utils 创建copy.js export const copy (val: string): void > {let { isSuccessRef } useCopyToClipboard(val) as anyif (isSuccessRef) {// 轻提示showNotify("复制…

【强化学习的数学原理】课程笔记--3(蒙特卡洛方法)

目录 蒙特卡洛方法MC Basic算法sparse reward MC Greedy 算法样本使用效率MC ϵ \epsilon ϵ-Greedy 算法一些例子 蒙特卡洛方法 第二节 推导贝尔曼最优公式中的&#xff1a; q π k ( s , a ) ∑ r P ( r ∣ s , a ) r γ ∑ s ′ P ( s ′ ∣ s , a ) v π k ( s ′ ) q…

vue3 ~ pinia学习

先看两个图 一个vuex 一个pinia 根据图看出来 pinia更简单了 那么具体怎么操作呢 我们来看下~ 第一步 下载 yarn add pinia # 或者使用 npm npm install pinia 第二步 注册 创建一个 pinia 实例 (根 store) 并将其传递给应用&#xff1a; import { createApp } from v…