04-netty基础-Reactor三种模型

1 基本概念

Reactor模型是一种事件驱动(Event-Driven)的设计模式,主要用于高效处理高并发、I/O密集型场景(如网络、服务器、分布式等)。其核心思想就是集中管理事件,将I/O操作与业务逻辑解耦,避免传统多线程模型中线程切换的开销,从而提升系统的吞吐量和响应速度。

核心目标:
在高并发场景下,传统的 “一连接一线程” 模型会因线程创建 / 销毁、上下文切换的开销过大而效率低下。Reactor 模型通过以下方式解决这一问题:

  • 单个或少量线程监听多个 I/O 事件(如网络连接、数据读写),避免线程资源浪费;
  • 仅当事件触发(如客户端发送数据)时才执行对应处理逻辑,实现 “事件就绪才处理” 的高效调度。

2 核心组件

 Reactor 模型的运行依赖四个关键组件,它们协同完成事件的检测、分发与处理:
1、事件源
产生事件的源头,通常是I/O相关的资源,例如:
网络套接字(Socket):客户端连接、数据发送/接收等事件的源头        
文件描述符(FD):文件读写、异常等事件的源头
2、事件多路分发器(Event Demultiplexer)
又称 “I/O 多路复用器”,是 Reactor 模型的 “感知器官”。
作用:持续监听多个事件源的事件(如 “可读”“可写”“异常”),当事件触发时标记为 “就绪”;
底层依赖:操作系统提供的 I/O 多路复用系统调用,如 Unix/Linux 的select/poll/epoll,或 BSD 的kqueue。

3、反应器(Reactor)
模型的 “核心调度者”,是事件处理的中枢。
作用:从事件多路分发器获取 “就绪事件”,根据事件类型和关联的事件源,分发给对应的事件处理器;
本质:通过 “事件注册 - 事件监听 - 事件分发” 的逻辑,实现对所有事件的集中管理。

4 事件处理器(Handler)
负责具体业务逻辑的 “执行者”。
作用:定义事件处理的回调方法(如handleRead处理可读事件、handleWrite处理可写事件),由 Reactor 触发执行;
特点:仅关注业务逻辑(如解析请求、生成响应),不关心事件的检测与分发。

3 单Reactor单线程模型

3.1 概念

        在单Reactor单线程模型中,他们的作用以及实现逻辑,首先客户端访问服务端,在服务端这边首先是使用Reactor监听accept事件和read事件,当有连接过来,就交给acceptor处理accept事件,当触发read事件,同时accept或把read事件交给handler处理。所有动作都是由一个线程完成的。

特点:单线程Reactor模型编程简单,比较适用于每个请求都可以快速完成的场景,但是不能发挥出多核CPU的优势,在一般情况下,不会使用单Reactor单线程模型。

3.2 原理图

3.3 代码实现

3.3.1 入口

入口: 启动Reactor线程

package com.bonnie.netty.reactor.single;import java.io.IOException;/*** 单Reactor单线程模型*/
public class Main {public static void main(String[] args) throws IOException {new Thread(new Reactor(8080, "Main-Thread")).start();}}

3.3.2 Reactor

1、启动服务端ServerSocketChannel
2、监听accept事件
3、监听read事件

package com.bonnie.netty.reactor.single;import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.util.Iterator;
import java.util.Set;/*** 模拟Reactor的单线程模型*/
public class Reactor implements Runnable {Selector selector;ServerSocketChannel serverSocketChannel;public Reactor(int port, String threadName) throws IOException {selector = Selector.open();serverSocketChannel = ServerSocketChannel.open();// 绑定端口serverSocketChannel.bind(new InetSocketAddress(port));// 设置成非阻塞serverSocketChannel.configureBlocking(Boolean.FALSE);// 注册OP_ACCEPT,事件,会调用Acceptor.run方法serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT, new Acceptor(selector, serverSocketChannel));}@Overridepublic void run() {while (!Thread.interrupted()) {try {// 阻塞selector.select();Set<SelectionKey> selectionKeys = selector.selectedKeys();Iterator<SelectionKey> iterator = selectionKeys.iterator();while (iterator.hasNext()) {// 我们之前说的分发事件就是这个地方分发了, 此处可能是accept事件,也可能是read事件dispatcher(iterator.next());// 分发完之后要删除key,防止重复keyiterator.remove();}} catch (IOException e) {throw new RuntimeException(e);}}}private void dispatcher(SelectionKey key) {// 然后在这里通过key获取这个attachment,执行他的run方法,记住,这里并没有开启线程,所有叫做单线程Reactor单线程模型Runnable runnable = (Runnable)key.attachment();if (runnable!=null) {runnable.run();}}}

 3.3.3 Acceptor

1、处理accept请求
2、把read事件转发给handler处理

package com.bonnie.netty.reactor.single;import java.io.IOException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;/*** 接收连接请求,并注册handle到selector*/
public class Acceptor implements Runnable{Selector selector;ServerSocketChannel serverSocketChannel;public Acceptor(Selector selector, ServerSocketChannel serverSocketChannel) {this.selector = selector;this.serverSocketChannel = serverSocketChannel;}@Overridepublic void run() {try {SocketChannel socketChannel = serverSocketChannel.accept();System.out.println(socketChannel.getRemoteAddress() + " 收到连接!!!");// 设置成非阻塞socketChannel.configureBlocking(Boolean.FALSE);// 注册事件,交由Handler处理socketChannel.register(selector, SelectionKey.OP_READ, new Handler(socketChannel));} catch (IOException e) {throw new RuntimeException(e);}}}

 3.3.4 Handler

处理read事件

package com.bonnie.netty.reactor.single;import java.io.IOException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;/*** 接收连接请求,并注册handle到selector*/
public class Acceptor implements Runnable{Selector selector;ServerSocketChannel serverSocketChannel;public Acceptor(Selector selector, ServerSocketChannel serverSocketChannel) {this.selector = selector;this.serverSocketChannel = serverSocketChannel;}@Overridepublic void run() {try {SocketChannel socketChannel = serverSocketChannel.accept();System.out.println(socketChannel.getRemoteAddress() + " 收到连接!!!");// 设置成非阻塞socketChannel.configureBlocking(Boolean.FALSE);// 注册事件,交由Handler处理socketChannel.register(selector, SelectionKey.OP_READ, new Handler(socketChannel));} catch (IOException e) {throw new RuntimeException(e);}}}

3.3.5 码云位置

git地址: https://gitee.com/huyanqiu6666/netty.git    分支: 250724-reactor

4 单Reactor多线程模型

4.1 概念

解决单Reactor单线程模型的不足,使用多线程处理handler提升处理能力,增加吞吐量。

4.2 原理图

4.3 代码实现

4.3.1 入口

package com.bonnie.netty.reactor.mult;import java.io.IOException;/*** 单reactor多线程模型:处理handle的时候是线程池*/
public class MultMain {public static void main(String[] args) throws IOException {new Thread(new MultReactor(8080, "Main-Thread")).start();}}

4.3.2 MultReactor

package com.bonnie.netty.reactor.mult;import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.util.Iterator;
import java.util.Set;/*** 模拟单Reactor多线程模型* 1、监听accept事件* 2、监听read事件*/
public class MultReactor implements Runnable {Selector selector;ServerSocketChannel serverSocketChannel;public MultReactor(int port, String threadName) throws IOException {selector = Selector.open();serverSocketChannel = ServerSocketChannel.open();// 绑定端口serverSocketChannel.bind(new InetSocketAddress(port));// 设置成非阻塞serverSocketChannel.configureBlocking(Boolean.FALSE);// 注册OP_ACCEPT,事件,会调用Acceptor.run方法serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT, new MultAcceptor(selector, serverSocketChannel));}@Overridepublic void run() {while (!Thread.interrupted()) {try {// 阻塞selector.select();Set<SelectionKey> selectionKeys = selector.selectedKeys();Iterator<SelectionKey> iterator = selectionKeys.iterator();while (iterator.hasNext()) {// 我们之前说的分发事件就是这个地方分发了, 此处可能是accept事件,也可能是read事件dispatcher(iterator.next());// 分发完之后要删除key,防止重复keyiterator.remove();}} catch (IOException e) {throw new RuntimeException(e);}}}private void dispatcher(SelectionKey key) {// 然后在这里通过key获取这个attachment,执行他的run方法,记住,这里并没有开启线程,所有叫做单线程Reactor单线程模型Runnable runnable = (Runnable)key.attachment();if (runnable!=null) {runnable.run();}}}

4.3.3 MultAcceptor

package com.bonnie.netty.reactor.mult;import java.io.IOException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;/*** 接收连接请求,并注册handle到selector* 1、处理accept事件* 2、read事件转发给handler*/
public class MultAcceptor implements Runnable{Selector selector;ServerSocketChannel serverSocketChannel;public MultAcceptor(Selector selector, ServerSocketChannel serverSocketChannel) {this.selector = selector;this.serverSocketChannel = serverSocketChannel;}@Overridepublic void run() {try {SocketChannel socketChannel = serverSocketChannel.accept();System.out.println(socketChannel.getRemoteAddress() + " 收到连接!!!");// 设置成非阻塞socketChannel.configureBlocking(Boolean.FALSE);// 注册事件,交由Handler处理socketChannel.register(selector, SelectionKey.OP_READ, new MultHandler(socketChannel));} catch (IOException e) {throw new RuntimeException(e);}}}

4.3.4 MultHandler

package com.bonnie.netty.reactor.mult;import org.apache.commons.lang3.StringUtils;import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;/*** Handler将read事件给线程池处理*/
public class MultHandler implements Runnable {private SocketChannel socketChannel;public MultHandler(SocketChannel socketChannel) {this.socketChannel = socketChannel;}private Executor executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2);@Overridepublic void run() {// 放到线程池中处理executor.execute(new ReadHandle(socketChannel));}private class ReadHandle implements Runnable{private SocketChannel socketChannel;public ReadHandle(SocketChannel socketChannel) {this.socketChannel = socketChannel;}@Overridepublic void run() {System.out.println("线程名称:" + Thread.currentThread().getName());// 定义一个ByteBuffer的数据结构ByteBuffer byteBuffer = ByteBuffer.allocate(1024);int len=0, total=0;String msg = StringUtils.EMPTY;try {do {len = socketChannel.read(byteBuffer);if (len > 0) {total += len;msg += new String(byteBuffer.array());}System.out.println(socketChannel.getRemoteAddress() + "客戶端的消息已收到," + msg);} while (len>byteBuffer.capacity());} catch (IOException e) {throw new RuntimeException(e);}}}}

4.3.5 码云位置

git地址: https://gitee.com/huyanqiu6666/netty.git    分支: 250724-reactor

5 主从Reactor模型

5.1 概念

5.2 原理图

5.3 代码实现

5.3.1 入口

package com.bonnie.netty.reactor.main;import java.io.IOException;/*** 主从Reactor多线程模型*/
public class MainMain {public static void main(String[] args) throws IOException {new Thread(new MainReactor(8080), "Main-Thread").start();}}

5.3.2 MainReactor

package com.bonnie.netty.reactor.main;import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.util.Iterator;
import java.util.Set;/*** 构建Selector、ServerSocketChannel绑定端口,设置成非阻塞* 注册accept事件*/
public class MainReactor implements Runnable {private final Selector selector;private final ServerSocketChannel serverSocketChannel;public MainReactor(int port) throws IOException {// 主Reactor负责监听accept事件selector = Selector.open();serverSocketChannel = ServerSocketChannel.open();serverSocketChannel.bind(new InetSocketAddress(port));serverSocketChannel.configureBlocking(Boolean.FALSE);// 添加attachment为acceptorserverSocketChannel.register(selector, SelectionKey.OP_ACCEPT, new MainAcceptor(serverSocketChannel));}@Overridepublic void run() {while (!Thread.interrupted()) {try {// 等待客户端的连接到来selector.select();Set<SelectionKey> selectionKeys = selector.selectedKeys();Iterator<SelectionKey> iterator = selectionKeys.iterator();while (iterator.hasNext()) {// 当有连接过来的时候就会转发任务dispatch(iterator.next());iterator.remove();}} catch (IOException e) {throw new RuntimeException(e);}}}private void dispatch(SelectionKey key) {// 可能拿到的对象有两个  Acceptor HandlerRunnable runnable = (Runnable)key.attachment();if (runnable!=null) {runnable.run();}}
}

5.3.3 SubReactor

package com.bonnie.netty.reactor.main;import java.io.IOException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.Iterator;
import java.util.Set;/*** 子Reactor*/
public class SubReactor implements Runnable{private Selector selector;public SubReactor(Selector selector) {this.selector = selector;}@Overridepublic void run() {while (true) {try {// 所有的子Reactor阻塞selector.select();System.out.println("selector:"+selector.toString()+"thread:"+Thread.currentThread().getName());Set<SelectionKey> selectionKeys = selector.selectedKeys();Iterator<SelectionKey> iterator = selectionKeys.iterator();while (iterator.hasNext()) {dispacher(iterator.next());iterator.remove();}} catch (IOException e) {throw new RuntimeException(e);}}}private void dispacher(SelectionKey selectionKey) {// 此处会调用workHandler里面的方法Runnable runnable = (Runnable) selectionKey.attachment();if (runnable!=null) {runnable.run();}}
}

5.3.4 MainAcceptor

package com.bonnie.netty.reactor.main;import java.io.IOException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;/*** 处理MainAcceptor请求*/
public class MainAcceptor implements Runnable{private ServerSocketChannel serverSocketChannel;private final Integer core = Runtime.getRuntime().availableProcessors() * 2;private Integer index = 0;private Selector[] selectors = new Selector[core];private SubReactor[] subReactors = new SubReactor[core];private Thread[] threads = new Thread[core];/*** 构造方法* 1、初始化多个SubReactor* 2、初始化多个Selector* 3、每个SubReactor都有一个Selector* 4、创建线程包装SubReactor* 5、启动线程,也就是调用每一个SubReactor的run方法*/public MainAcceptor(ServerSocketChannel serverSocketChannel) throws IOException {this.serverSocketChannel = serverSocketChannel;for (int i=0; i<core; i++) {selectors[i] = Selector.open();subReactors[i] = new SubReactor(selectors[i]);threads[i] = new Thread(subReactors[i]);// 一初始化就工作起来threads[i].start();}}@Overridepublic void run() {try {System.out.println("acceptor thread: " + Thread.currentThread().getName());// 此处就会接收连接的socketChannelSocketChannel socketChannel = serverSocketChannel.accept();System.out.println("有客户端上来了:"+socketChannel.getRemoteAddress());socketChannel.configureBlocking(Boolean.FALSE);// 立即唤醒第一个阻塞的selectorselectors[index].wakeup();// 然后注册Read事件到该selectorsocketChannel.register(selectors[index], SelectionKey.OP_READ, new WorkHandler(socketChannel));index = (++index) % core;} catch (IOException e) {throw new RuntimeException(e);}}
}

5.3.5 WorkHandler

package com.bonnie.netty.reactor.main;import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;/*** SubReactor把事件交给WorkHandler去执行*/
public class WorkHandler implements Runnable{private SocketChannel socketChannel;public WorkHandler(SocketChannel socketChannel) {this.socketChannel = socketChannel;}@Overridepublic void run() {try {System.out.println("WorkHandler thread:" + Thread.currentThread().getName());ByteBuffer buffer = ByteBuffer.allocate(1024);// 数据读取到socketChannel中socketChannel.read(buffer);String msg = new String(buffer.array(), StandardCharsets.UTF_8);System.out.println(socketChannel.getRemoteAddress() + "发来了消息:" + msg);// 给客户端会写消息socketChannel.read(ByteBuffer.wrap("你的消息已收到".getBytes(StandardCharsets.UTF_8)));} catch (IOException e) {throw new RuntimeException(e);}}
}

5.3.6 码云位置

git地址: https://gitee.com/huyanqiu6666/netty.git    分支: 250724-reactor



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

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

相关文章

踩坑无数!NFS服务从入门到放弃再到真香的血泪史

前言 说起NFS&#xff0c;我估计很多搞运维的兄弟都有一肚子话要说。这玩意儿吧&#xff0c;看起来简单&#xff0c;用起来坑多&#xff0c;但是真正搞明白了又觉得挺香的。 前几天有个朋友问我&#xff0c;说他们公司要搭建一个文件共享系统&#xff0c;问我推荐什么方案。我…

矩阵谱分解的证明及计算示例

1. 矩阵谱分解的条件矩阵的谱分解&#xff08;也称为特征分解&#xff09;是将一个矩阵分解为一系列由其特征向量和特征值构成的矩阵乘积的过程。进行谱分解的前提条件包括&#xff1a;<1.> 矩阵是可对角化的&#xff08;Diagonalizable&#xff09;&#xff0c;即矩阵存…

Leetcode 07 java

169. 多数元素 给定一个大小为 n 的数组 nums &#xff0c;返回其中的多数元素。 多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。 你可以假设数组是非空的&#xff0c;并且给定的数组总是存在多数元素。 示例 1&#xff1a; 输入&#xff1a;nums [3,2,3] 输出&a…

CS231n-2017 Lecture6训练神经网络(一)笔记

本节主要讲的是模型训练时的算法设计数据预处理&#xff1a;关于数据预处理&#xff0c;我们有常用的3个符号&#xff0c;数据矩阵X&#xff0c;假设其尺寸是&#xff0c;N是数据样本的数量&#xff0c;D是数据的维度均值减法(Mean subtraction)&#xff1a;是预处理最常用的形…

C++ 中实现 `Task::WhenAll` 和 `Task::WhenAny` 的两种方案

&#x1f4da; C 中实现 Task::WhenAll 和 Task::WhenAny 的两种方案 引用&#xff1a; 拈朵微笑的花 想一番人世變換 到頭來輸贏又何妨日與夜互消長 富與貴難久長 今早的容顏老於昨晚C 标准库异步编程示例&#xff08;一&#xff09;C TAP&#xff08;基于任务的异步编程…

【学习】Codeforces Global Round 15 C. Maximize the Intersections

题意&#xff1a;给出一个圆&#xff0c;顺时针排布1~2*n&#xff0c;已知连了k条边&#xff0c;问这个圆最好情况下有多少个线的交点&#xff0c;要求线与线之间不能有重复的连接点&#xff0c;也就是每个点只能被一条线连接 思路&#xff1a; 1.考虑没有线的时候&#xff0…

图论:Dijkstra算法

昨天介绍了最小生成树的两个算法&#xff0c;最小生成树的两个算法旨在求解无向有权图中的最小代价联通图的问题&#xff0c;那么对于有向有权图&#xff0c;从起点到终点的最小花费代价问题就可以用 Dijkstra 算法来解决而且Dijkstra算法可以求出来从起始点开始到所有节点的最…

WPFC#超市管理系统(2)顾客管理、供应商管理、用户管理

超市管理系统3. 顾客管理3.1 顾客新增3.2 DataGrid样式3.3 顾客删除3.4 顾客修改4. 供应商管理4.1 供应商管理主界面4.2 新增供应商4.3 修改供应商5. 用户管理5.1 用户管理主界面5.2 新增用户5.3 修改用户总结3. 顾客管理 在CustomerView.xaml使用命令绑定方式添加页面加载Loa…

Windows本地部署DeepSeek

1、Ollama1、下载Ollama安装包https://ollama.com/download&#xff08;如果下载很慢 可以直接找我拿安装包&#xff09;2、使用命令行安装打开cmd 将下载的安装包OllamaSetup.exe 放到想要安装的目录下。&#xff08;如果直接双击&#xff0c;会装到C盘&#xff09;例如想装到…

基于Python的新闻爬虫:实时追踪行业动态

引言 在信息时代&#xff0c;行业动态瞬息万变。金融从业者需要实时了解政策变化&#xff0c;科技公司需要跟踪技术趋势&#xff0c;市场营销人员需要掌握竞品动向。传统的人工信息收集方式效率低下&#xff0c;难以满足实时性需求。Python爬虫技术为解决这一问题提供了高效方…

阿里视频直播解决方案VS(MediaMTX + WebRTC) 流媒体解决方案

背景&#xff1a; 公司采购了新的摄像头&#xff0c;通过rtsp或者rtmp推流到云平台&#xff0c;云平台内部进行转码处理&#xff0c;客户端使用HLS或HTTP-FLV播放&#xff0c;移动App可能使用HLS或私有SDK&#xff0c;超低延时则采用WebRTC。 技术选型&#xff1a; RTSP&…

day33:零基础学嵌入式之网络——TCP并发服务器

一、服务器1.服务器分类单循环服务器&#xff1a;只能处理一个客户端任务的服务器并发服务器&#xff1a;可同时处理多个客户端任务的服务器二、TCP并发服务器的构建1.如何构建&#xff1f;&#xff08;1&#xff09;多进程&#xff08;每一次创建都非常耗时耗空间&#xff0c;…

VR全景制作的流程?VR全景制作可以用在哪些领域?

VR全景制作的流程&#xff1f;VR全景制作可以用在哪些领域&#xff1f;VR全景制作&#xff1a;流程、应用与未来虚拟现实&#xff08;VR&#xff09;全景制作正迅速改变我们的感官体验&#xff0c;使我们能够身临其境地探索虚拟世界&#xff0c;享受沉浸式的奇妙感受。那么&…

用LangChain重构客服系统:腾讯云向量数据库+GPT-4o实战

人们眼中的天才之所以卓越非凡&#xff0c;并非天资超人一等而是付出了持续不断的努力。1万小时的锤炼是任何人从平凡变成超凡的必要条件。———— 马尔科姆格拉德威尔 目录 一、传统客服系统痛点与重构价值 1.1 传统方案瓶颈分析 1.2 新方案技术突破点 二、系统架构设计&…

主要分布在腹侧海马体(vHPC)CA1区域(vCA1)的混合调谐细胞(mixed-tuning cells)对NLP中的深层语义分析的积极影响和启示

腹侧海马体CA1区&#xff08;vCA1&#xff09;的混合调谐细胞&#xff08;mixed-tuning cells&#xff09;通过整合情感、社会关系、空间概念等多模态信息&#xff0c;形成动态的情景化语义表征&#xff0c;为自然语言处理&#xff08;NLP&#xff09;的深层语义分析提供了重要…

ESP32的ADF详解:6. Audio Processing的API

一、Downmix 1. 核心功能 将基础音频流和新加入音频流混合为单一输出流&#xff0c;支持动态增益控制和状态转换。输出声道数与基础音频一致&#xff0c;新加入音频自动转换声道匹配。2. 关键特性声道处理 输出声道数 基础音频声道数新加入音频自动转换声道&#xff08;如立体…

Qt(基本组件和基本窗口类)

一、基本组件1. Designer设计师为什么要上来先将这个东西呢&#xff0c;这个是QT外置的设计界面的工具&#xff0c;没啥用&#xff0c;所以了解一下。我们用的多的是QT内置的界面设计&#xff0c;只需要我们双击我们创建的项目的.ui文件就可以进入这个界面&#xff0c;你对界面…

docker与k8s的容器数据卷

Docker容器数据卷 特性 docker镜像由多个只读层叠加而成&#xff0c;启动容器时&#xff0c;Docker会加载只读镜像层并在镜像栈顶部添加一个读写层。如果运行中的容器修改了现有的一个已经存在的文件&#xff0c;那么该文件将会从读写层下面的只读层复制到读写层&#xff0c;该…

自然语言处理技术应用领域深度解析:从理论到实践的全面探索

1. 引言:自然语言处理的技术革命与应用前景 自然语言处理(Natural Language Processing,NLP)作为人工智能领域的核心分支,正在以前所未有的速度改变着我们的数字化生活。从最初的规则基础系统到如今基于深度学习的大语言模型,NLP技术经历了从理论探索到实际应用的深刻变…

OpenGLRender开发记录(二): 阴影(shadowMap,PCF,PCSS)

目录已实现功能阴影shadowMapPCFPCSS实现shadowMapPCFPCSS阴影GitHub主页&#xff1a;https://github.com/sdpyy1 OpenGLRender:https://github.com/sdpyy1/CppLearn/tree/main/OpenGL 已实现功能 除了上次实现IBL之外&#xff0c;项目目前新增了imGUI的渲染&#xff0c;更方便…