netty基础与原理

Netty线程模型和Reactor模式

简介:reactor模式 和 Netty线程模型

设计模式——Reactor模式(反应器设计模式),是一种基于 事件驱动的设计模式,在事件驱动的应用中,将一个或多个客户的 服务请求分离(demultiplex)和调度(dispatch)给应用程序。在 事件驱动的应用中,同步地、有序地处理同时接收的多个服务请求 一般出现在高并发系统中,比如Netty,Redis等。

通俗理解:KTV例子 前台接待,服务人员带领去开机器. Reactor模式基于事件驱动,适合处理海量的I/O事件,属于同步非阻塞IO(NIO)

优点

  1. 响应快,不会因为单个同步而阻塞,虽然Reactor本身依然 是同步的;

  2. 编程相对简单,最大程度的避免复杂的多线程及同步问题, 并且避免了多线程/进程的切换开销;

  3. 可扩展性,可以方便的通过增加Reactor实例个数来充分利 用CPU资源;

缺点

  1. 相比传统的简单模型,Reactor增加了一定的复杂性,因而 有一定的门槛,并且不易于调试。
  2. Reactor模式需要系统底层的的支持,比如Java中的 Selector支持,操作系统的select系统调用支持

Reactor单线程模型( 比较少用)

1)作为NIO服务端,接收客户端的TCP连接;作为NIO客户 端,向服务端发起TCP连接;

2)服务端读请求数据并响应;客户端写请求并读取响应

使用场景:

对应小业务则适合,编码简单;对于高负载、大并发的应用场 景不适合,一个NIO线程处理太多请求,则负载过高,并且可能响应 变慢,导致大量请求超时,而且万一线程挂了,则不可用了

Reactor多线程模型

内容:

1)一个Acceptor线程,一组NIO线程,一般是使用自带的线程池,包含一个任务队列和多个可用的线程

使用场景:

可满足大多数场景,但是当Acceptor需要做复杂操作的时候, 比如认证等耗时操作,再高并发情况下则也会有性能问题

Reactor主从线程模型

内容:

Acceptor不再是一个线程,而是一组NIO线程;IO线程也 是一组NIO线程,这样就是两个线程池去处理接入连接和处理IO
使用场景: 满足目前的大部分场景,也是Netty推荐使用的线程模型 BossGroup WorkGroup

补充:

为什么Netty使用NIO而不是AIO,是同步非阻塞还是异步非阻塞?

答:在Linux系统上,AIO的底层实现仍使用EPOLL,与NIO相同,因此在性能上没有明显的优势.

Netty整体架构是reactor模型, 采用epoll机制,所以往深的说,还是IO多路复用模式,所以也可说 netty是同步非阻塞模型

很多人说这是netty是基于Java NIO 类库实现的异步通讯框架

特点:异步非阻塞、基于事件驱动,性能高,高可靠性和高可定制 性。

Netty快速上手案例

Echo服务和Netty项目搭建

  1. 什么是Echo服务:就是一个应答服务(回显服务器),客户端发 送什么数据,服务端就响应的对应的数据是一个非常有的用于调试 和检测的服务
  2. maven依赖地址:https://mvnrepository.com/artifact/io.netty/netty-all/4.1.32.Final

io.netty netty-all 4.1.32.Final

Echo服务-服务端程序编写 对应的启动类和handler处理器:

EchoServer.java

/** 
 * @Description: Echo服务端 
 */ 
public class EchoServer {
    private int port;// 服务端端口号  
    public EchoServer(int port) { 
        this.port = port;
    }
    
    /**   * 启动服务的run 方法   */ 
    public void run() throws InterruptedException { 
        // 配置服务端线程组   
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();        // 老板:后台线程组    
        NioEventLoopGroup workGroup = new NioEventLoopGroup();        // 员工:前台线程组  
        try {   
            ServerBootstrap serverBootstrap = new ServerBootstrap();// 服务启动引导类
            serverBootstrap.group(bossGroup,workGroup)         // 线程组交给服务引导类
                .channel(NioServerSocketChannel.class)         //指定服务端和客户端链接的管道
                .childHandler(         
                new ChannelInitializer() {                // 自定义个handler
                    protected void initChannel(SocketChannel socketChannel) throws Exception {                 							// 添加自己创建的 EchoServerHandler 逻辑                     
                        socketChannel.pipeline().addLast(
                            new EchoServerHandler());    
                    }          
                }); 
            System.out.println("Echo 服务器启动 ing...");       //绑定端口,同步等待成功     
            ChannelFuture channelFuture = serverBootstrap.bind(port).sync();       //等待服务端监听端口关闭
            channelFuture.channel().closeFuture().sync();
       }finally {
            //优雅退出,释放线程池
            workGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
       }
   }
    public static void main(String [] args)
        throws InterruptedException {
        int port = 8080;
        if(args.length > 0){
            port = Integer.parseInt(args[0]);
       }
        new EchoServer(port).run();
   }
}

EchoServerHandler.java

/**
* @Auther: csp1999
* @Date: 2020/09/17/21:15
* @Description: Echo服务端逻辑处理器
*/
public class EchoServerHandler extends ChannelInboundHandlerAdapter {
    /*
     * 从管道中读取数据
     * @param: ctx
     * @param: msg
     * @return: void
     */
      @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg)
        throws Exception {
        ByteBuf data = (ByteBuf) msg;
        System.out.println("服务端收到数据: " + data.toString(CharsetUtil.UTF_8));
        ctx.writeAndFlush(data);
   }
    /*
     * 从管道中读取数据完毕
     * @param: ctx
     * @return: void
     */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        System.out.println("EchoServerHandlechannelReadComplete 从管道中读取数据完毕...");
   }
    /*
     * 异常捕获
     * @param: ctx
     * @param: cause
     * @return: void
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx,Throwable cause) throws Exception {
        cause.printStackTrace();// 打印异常
        ctx.close();
   }
}

EchoClient.java

/** 
 * @Description: echo 客户端 
 */ 
public class EchoClient {  
    private String host;// 客户端ip   
    private int port;// 客户端端口号
    public EchoClient(String host, int port) {
        this.host = host; 
        this.port = port;
    }   
    
    /**   * 启动服务的run 方法   */  
    public void run() throws InterruptedException {  
        // 定义线程组    
        EventLoopGroup group = new NioEventLoopGroup();
        try { 
            Bootstrap bootstrap = new Bootstrap();       // 客户端服务启动引导类 
            bootstrap.group(group)// 线程组交给服务 引导类    
                .channel(NioSocketChannel.class)         // 指定服务端和客户端链接的管道 NioServerSocketChannel
                .remoteAddress(new InetSocketAddress(host, port))// 地址和端口     
                .handler( 
                	new ChannelInitializer() {   
                        protected void initChannel(SocketChannel ch) throws Exception {    
                            // EchoClientHandler 逻辑  
                            ch.pipeline().addLast(new EchoClientHandler());
                        }
                    });
            //连接到服务端,connect是异步连接,在调用同步 等待sync,等待连接成功 
            ChannelFuture channelFuture = bootstrap.connect().sync();       //阻塞直到客户端通道关闭    
            channelFuture.channel().closeFuture().sync();  
        } finally {  
            //优雅退出,释放NIO线程组 
            group.shutdownGracefully();
        }  
    }
    
    public static void main(String[] args) throws InterruptedException { 
        new EchoClient("127.0.0.1", 8080).run();  
    }
}

EchoClientHandler.java

/**
* @Description: echo 客户端逻辑处理器
*/
public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
    protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
        System.out.println("Client received 客户端收到的数据: " + msg.toString(CharsetUtil.UTF_8));
   }
    /*
     * 管道激活
     * @param: ctx
     * @return: void
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("Active 管道激活...");
        ctx.writeAndFlush(Unpooled.copiedBuffer("711 改了密码:",CharsetUtil.UTF_8));
   }
    /*
     * 管道数据读取完毕
     * @param: ctx
     * @return: void
     */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        System.out.println("EchoClientHandlerchannelReadComplete 管道读取完毕...");
   }
    /*
     * 异常捕获
     * @param: ctx
     * @param: cause
     * @return: void
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwablecause) throws Exception {
      cause.printStackTrace();// 抛出异常
      ctx.close();
 }
}

核心链路源码

EventLoop和EventLoopGroup线程模型
1)高性能RPC框架的3个要素:IO模型、数据协议、线程模型。
2)EventLoop 就是一个线程,1个 EventLoop 可以服务多个Channel 管道,1个 Channel 只有一个EventLoop;可以创建多个 EventLoop 来优化资源利用,也就是EventLoopGroup。
3)EventLoopGroup 负责分配 EventLoop 到新创建的Channel。

4)源码分析默认线程池数量 = CPU 核数*2

# EventLoop -> 维护一个 Selector(单线程的方 式管理多个Channel)

学习资料:http://ifeve.com/selectors/

\2. Netty启动引导类Bootstrap模块

简介:Netty启动引导类Bootstrap作用和tcp通道参数设置

参考:https://blog.csdn.net/QH_JAVA/article/details/78383543

ServerBootstrap serverBootstrap = new ServerBootstrap();
  • group : 设置线程组模型,Reactor 线程模型对比 EventLoopGroup 1. 单线程 2. 多线程 3. 主从线程 参考:https://blog.csdn.net/QH_JAVA/article/details/784436 46
  • channal 设置channel通道类型NioServerSocketChannel、 OioServerSocketChannel
  • option: 作用于每个新建立的 channel,设置TCP连接中的一些 参数,如下:
    • ChannelOption.SO_BACKLOG: 存放已完成三次握手的请求 的等待队列的最大长度;
    • ChannelOption.TCP_NODELAY: 为了解决Nagle的算法问 题,默认是false, 要求高实时性,有数据时马上发送,就将 该选项设置为true关闭Nagle算法;如果要减少发送次数,就 设置为false,会累积一定大小后再发送;
  • childOption: 作用于被accept之后的连接
  • childHandler: 用于对每个通道里面的数据处理

Channel模块

简介: Channel 的作用,核心模块,生命周期等

  • Channel: 客户端和服务端建立的一个连接通道
  • ChannelHandler: 负责Channel的逻辑处理
  • ChannelPipeline: 负责管理ChannelHandler的有序容器

他们是什么关系:

一个Channel包含一个ChannelPipeline,所有ChannelHandler 都会顺序加入到ChannelPipeline中.

创建Channel时会自动创建一 个ChannelPipeline,每个Channel都有一个管理它的pipeline, 这关联是永久性的。

Channel当状态出现变化,就会触发对应的事件:

状态:

  • channelRegistered: channel注册到一个EventLoop
  • channelActive: 变为活跃状态(连接到了远程主机),可以接受 和发送数据
  • channelInactive: channel处于非活跃状态,没有连接到远程主 机
  • channelUnregistered: channel已经创建,但是未注册到一个 EventLoop里面,也就是没有和Selector绑定

例如:

@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
    System.out.println("Active 管道激活...");
    ctx.writeAndFlush(Unpooled.copiedBuffer("711改了密码:", CharsetUtil.UTF_8));   
}

ChannelHandler和ChannelPipeline模块

简介:ChannelHandler和ChannelPipeline核心作用和生命周期

方法:

  • handlerAdded : 当 ChannelHandler 添加到 ChannelPipeline 调用
  • handlerRemoved : 当 ChannelHandler 从 ChannelPipeline 移除时调用
  • exceptionCaught : 执行抛出异常时调用

Netty异步操作模块ChannelFuture

Netty中的所有I/O操作都是异步的,这意味着任何I/O调用都会立即返回,而ChannelFuture会提供有关的信息I/O操作的结果或状态。

ChannelFuture状态:

  • 未完成:当I/O操作开始时,将创建一个新的对象,新的最初 是未完成的 - 它既没有成功,也没有被取消,因为I/O操作尚 未完成。
  • 已完成:当I/O操作完成,不管是成功、失败还是取消, Future都是标记为已完成的, 失败的时候也有具体的信息,例 如原因失败,但请注意,即使失败和取消属于完成状态。

注意:不要在IO线程内调用future对象的sync或者await方 法,不能在channelHandler中调用sync或者await方法。

ChannelPromise:继承于ChannelFuture,进一步拓展用于设 置IO操作的结果

Netty网络数据传输编码与解码

什么是编码、解码

高性能RPC框架的3个要素:IO模型、数据协议、线程模型

最开始接触的编码:java序列化/反序列化(就是编解码)、url编 码、base64编解码

为啥jdk有编解码,还要netty自己开发编解码?( java自带序列化 的缺点 )

  1. 无法跨语言
  2. 序列化后的码流太大,也就是数据包太大
  3. 序列化和反序列化性能比较差

业界里面也有其他编码框架: google的 protobuf(PB)、 Facebook的Trift、Jboss的Marshalling、Kyro等

Netty里面的编解码:

  • 解码器:负责处理入站 InboundHandler数据
  • 编码器:负责出站 OutboundHandler 数据

Netty里面提供默认的编解码器,也支持自定义编解码器:

  • Encoder:编码器
  • Decoder:解码器
  • Codec:编解码器

Netty的解码器Decoder和使用场景

:Decoder对应的就是ChannelInboundHandler,主要就是字节数组 转换为消息对象。

主要是两个方法:

  • decode :一般都使用该方式

  • decodeLast:用于最后的几个字节处理,也就是channel 关闭 的时候,产生的最后一个消息。

抽象解码器 :

  • ByteToMessageDecoder:用于将字节转为消息,需要检查缓 冲区是否有足够的字节。

  • ReplayingDecoder:继承ByteToMessageDecoder,不需要检 查缓冲区是否有足够的字节,但是R速度略慢 于ByteToMessageDecoder,不是所有的ByteBuf都支持。

  • MessageToMessageDecoder:用于从一种消息解码为另外一 种消息(例如:POJO到POJO)

选择:项目复杂性高则使用ReplayingDecoder,否则使用 ByteToMessageDecoder

解码器具体的实现,用的比较多的是(更多是为了解决TCP底层的粘 包和拆包问题): DelimiterBasedFrameDecoder: 指定消息分隔符的解码器 xxx&aaa&bbb

  • LineBasedFrameDecoder: 以换行符为结束标志的解码器

  • FixedLengthFrameDecoder:固定长度解码器

  • LengthFieldBasedFrameDecoder:message = header+body, 基于长度解码的通用解码器

  • StringDecoder:文本解码器,将接收到的对象转化为字符串, 一般会与上面的进行配合,然后在后面添加业务handle

Netty编码器Encoder

Encoder对应的就是ChannelOutboundHandler,消息对象转换为 字节数组。

Netty本身未提供和解码一样的编码器,是因为场景不同,两者非对 等的:

  • MessageToByteEncoder:消息转为字节数组,调用write方 法,会先判断当前编码器是否支持需要发送的消息类型,如果不 支持,则透传;

  • MessageToMessageEncoder:用于从一种消息编码为另外一 种消息(例如POJO到POJO)

数据协议处理之Netty编解码器类Codec

组合解码器和编码器,以此提供对于字节和消息都相同的操作。

优点:成对出现,编解码都是在一个类里面完成。

缺点:耦合在一起,拓展性不佳

  • Codec:组合编解码

    • ByteToMessageCodec

    • MessageToMessageCodec

  • decoder:解码

    • ByteToMessageDecoder

    • MessageToMessageDecoder

  • encoder:编码

    • ByteToMessageEncoder

    • MessageToMessageEncoder

网络传输TCP粘包拆包

什么是TCP粘包拆包?

TCP拆包: 一个完整的包可能会被TCP拆分为多个包进行发送

TCP粘包: 把多个小的包封装成一个大的数据包发送, client发送的若干数据包 Server接收时粘成一包

发送方和接收方都可能出现这种情况:

发送方的原因:TCP默认会使用Nagle算法

接收方的原因: TCP接收到数据放置缓存中,应用程序从缓存中 读取

UDP: 是没有粘包和拆包的问题,有边界协议

TCP半包读写常见解决方案

发送方:可以关闭Nagle算法

接受方:TCP是无界的数据流,并没有处理粘包现象的机制, 且协议 本身无法避免粘包,半包读写的发生需要在应用层进行处理,应用 层解决半包读写的办法。

  • 设置定长消息 (10字符): xdclass000xdclass000xdclass000xdclass000

  • 设置消息的边界 ($$ 切割): sdfafwefqwefwe$$dsafadfadsfwqehidwuehfiw$$879329832 r89qweew$$

  • 使用带消息头的协议,消息头存储消息开始标识及消息的长度信 息:Header+Body

Netty自带解决TCP半包读写方案

  • DelimiterBasedFrameDecoder: 指定消息分隔符的解码器
  • LineBasedFrameDecoder: 以换行符为结束标志的解码器
  • FixedLengthFrameDecoder:固定长度解码器(Netty 使用该解 码器)
  • LengthFieldBasedFrameDecoder:message = header+body, 基于长度解码的通用解码器
  • herzbeat的笑脸?

HashedWheelTimer

时间轮算法管理延迟任务队列

在网络通信中管理上万的连接,每个连接都有超时任务,如果为每个任务启动一个TImer超时器,那么会占用大量资源。为了解决这个问题,可用Netty工具类HashedWheelTimer。

  • 类似前端setTimeout那样的超时任务?
  • 为什么每个连接都超时任务的话占用大量资源?一个单独的又好在哪里?网络通信中有什么地方需要超时任务?can can netty
  • 超超我的
  • 为什么网络连接有超时任务?

这个类用来计划执行非精准的I/O超时。可以通过指定每一格的时间间隔来改变执行时间的精确度。在大多数网络应用中,I/O超时不需要十分准确,因此,默认的时间间隔是100 毫秒,这个值适用于大多数场合。HashedWheelTimer内部结构可以看做是个车轮,简单来说,就是TimerTask的hashTable的车轮。车轮的size默认是512,可以通过构造函数自己设置这个值。注意,当HashedWheelTimer被实例化启动后,会创建一个新的线程,因此,你的项目里应该只创建它的唯一一个实例。

(这个类源自一位教授的论文 Tony Lauck)

意思是说,时间间隔越小精度越高?因为没必要完全精准,所以用时间轮每隔一段时间去处理?

看起来是单例模式

辞典

接口和实现类

  • Timer 计时器,负责总管TimeOut和TimeTask
    • HashedWheelTimer 将任务散列成一个环(底层是数组)来管理,每个散列桶双向链表串联TimeTask
  • TimeOut 一段延迟后只执行一次的任务,类似前端的setTimeout任务
  • TimeTask 被设置于TimeOut中的具体的任务

tick: 时钟“嘀嗒”一声,代表时间轮转动一下,到下一个hash桶

提交任务的线程,只要把任务往虚线上面的任务队列中存放即可返回。工作线程是单线程,一旦开启,不停地在时钟上绕圈圈。

超时任务设置为1000毫秒,超时之后,由hashedWheelTimer类中的worker线程,执行超时之后的任务。

hashedWheelTimer有32个槽(类比HashMap中的桶),默认每100毫秒移动下一个槽。
任务需要经过的tick数为: 1000 / 100 = 10次 (等待时长 / tickDuration)
任务需要经过的轮数为 : 10次 / 32次/轮 = 0轮 (tick总次数 / ticksPerWheel)

因为任务超时后不能马上被worker线程执行,需要等到worker线程移到相应卡槽位置时才会执行,因此说执行时间不精确。

  • 啊?那我们刚才算的是个什么啊?

hashedWheelTimer的核心是Worker线程,主要负责每过tickDuration时间就累加一次tick. 同时, 也负责执行到期的timeout任务, 此外,还负责添加timeou任务到指定的wheel中。

TimerTask 非常简单,就一个 run() 方法:

public interface TimerTask {
    void run(Timeout timeout) throws Exception;
}

这里有点意思的是,它把 Timeout 的实例也传进来了,我们平时的代码习惯,都是单向依赖。

这样做也有好处,那就是在任务执行过程中,可以通过 timeout 实例来做点其他的事情。

Timeout 也是一个接口类:

public interface Timeout {
    Timer timer();
    TimerTask task();
    boolean isExpired();
    boolean isCancelled();
    boolean cancel();
}

它持有上层的 Timer 实例,和下层的 TimerTask 实例,然后取消任务的操作也在这里面。

使用案例

Dubbo 的集群调用策略 FailbackClusterInvoker 中:

它在调用 provider 失败以后,返回空结果给消费端,然后由后台线程执行定时任务重试,多用于消息通知这种场景。

  • 那么其他的降级是怎么实现的?
  • feture和Promise?

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Verilog求log10和log2近似

Verilog求log10和log2近似 Verilog求10对数近似方法&#xff0c;整数部分用位置index代替&#xff0c;小数部分用查找表实现 参考&#xff1a; Verilog写一个对数计算模块Log2(x) FPGA实现对数log2和10*log10

【LangChain学习】基于PDF文档构建问答知识库(三)实战整合 LangChain、OpenAI、FAISS等

接下来&#xff0c;我们开始在web框架上整合 LangChain、OpenAI、FAISS等。 一、PDF库 因为项目是基于PDF文档的&#xff0c;所以需要一些操作PDF的库&#xff0c;我们这边使用的是PyPDF2 from PyPDF2 import PdfReader# 获取pdf文件内容 def get_pdf_text(pdf):text "…

SQL常见命令语句

1.连接数据库 mysql (-h IP) -u root -p 密码2.查看数据库 show databases3.使用数据库 use db_name4.查看表 show tables [from db_name]5.查看表结构 desc tb_name6.创建、删除、选择数据库 create database db_namedrop database db_nameuse db_name7.数据类型 参考链…

技术应用:Docker安全性的最佳实验|聊聊工程化Docker

&#x1f525; 技术相关&#xff1a;《技术应用》 ⛺️ I Love you, like a fire! 文章目录 首先&#xff0c;使用Docker Hub控制访问其次&#xff0c;保护密钥写在最后 不可否认&#xff0c;能生存在互联网上的软件都是相互关联的&#xff0c;当我们开发一款应用程序时&#x…

(二)结构型模式:1、适配器模式(Adapter Pattern)(C++实现示例)

目录 1、适配器模式&#xff08;Adapter Pattern&#xff09;含义 2、适配器模式应用场景 3、适配器模式的UML图学习 4、C实现适配器模式的示例 1、适配器模式&#xff08;Adapter Pattern&#xff09;含义 将一个接口转换为客户端所期待的接口&#xff0c;从而使两个接口…

JVM 查看配置 jinfo 及使用 jstat,查看堆栈jstack及GC

1. Jinfo 查看正在运行的Java应用程序的扩展参数: 包含 JVM 参数与 java 系统参数 命令&#xff1a; jinfo pid 2 jstat 查看堆内存使用情况及 GC 回收频率等&#xff1a; jstat [-命令选项] [vmid] [间隔时间(毫秒)] [查询次数] 2.1 jstat -gc pid 最常用&#xff0c;可…

MySQL数据库----------安装anaconda---------python与数据库的链接

作者前言 &#x1f382; ✨✨✨✨✨✨&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f382; ​&#x1f382; 作者介绍&#xff1a; &#x1f382;&#x1f382; &#x1f382; &#x1f389;&#x1f389;&#x1f389…

【Linux】进程间通信之管道

【Linux】进程间通信之管道 进程间通信进程间通信目的进程间通信的方式 管道&#xff08;内核维护的缓冲区&#xff09;匿名管道&#xff08;用于父子间进程间通信&#xff09;简单使用阻塞状态读写特征非阻塞状态读写特征 匿名管道特点命名管道 匿名管道与命名管道的区别 进程…

时序预测 | MATLAB实现基于CNN卷积神经网络的时间序列预测-递归预测未来(多指标评价)

时序预测 | MATLAB实现基于CNN卷积神经网络的时间序列预测-递归预测未来(多指标评价) 目录 时序预测 | MATLAB实现基于CNN卷积神经网络的时间序列预测-递归预测未来(多指标评价)预测结果基本介绍程序设计参考资料 预测结果 基本介绍 1.Matlab实现CNN卷积神经网络时间序列预测未…

中国首款量子计算机操作系统本源司南 PilotOS正式上线

中国安徽省量子计算工程研究中心近日宣布&#xff0c;中国国产量子计算机操作系统本源司南 PilotOS 客户端正式上线。 如果把量子芯片比喻成人的“心脏”&#xff0c;那么量子计算机操作系统就相当于人的“大脑”&#xff0c;量子计算应用软件则是人的“四肢”。 据安徽省量子…

C++入门篇7---string类

所谓的string类&#xff0c;其实就是我们所说的字符串&#xff0c;本质和c语言中的字符串数组一样&#xff0c;但是为了更符合C面向对象的特性&#xff0c;特地将它写成了一个单独的类&#xff0c;方便我们的使用 对其定义有兴趣的可以去看string类的文档介绍&#xff0c;这里…

运维监控学习笔记3

DELL的IPMI页面的登录&#xff1a; 风扇的状态&#xff1a; 电源温度&#xff1a;超过70度就告警&#xff1a; 日志信息&#xff1a; 可以看到更换过磁盘。 iDRAC的设置 虚拟控制台&#xff1a;启动远程控制台&#xff1a; 可以进行远程控制。 机房工程师帮我们接远程控制&…

opencv 基础54-利用形状场景算法比较轮廓-cv2.createShapeContextDistanceExtractor()

注意&#xff1a;新版本的opencv 4 已经没有这个函数 cv2.createShapeContextDistanceExtractor() 形状场景算法是一种用于比较轮廓或形状的方法。这种算法通常用于计算两个形状之间的相似性或差异性&#xff0c;以及找到最佳的匹配方式。 下面是一种基本的比较轮廓的流程&…

Dynamic CRM开发 - 实体介绍

实体简介 在CRM中,实体(Entity)是数据的基本载体,也是构建业务逻辑网络的基础节点。 实体可以理解为数据库中的一张表(实体中的字段对应数据库表的字段),比如创建一个实体存储客户信息,创建一个实体存储产品信息,产品实体里可以创建一个查找类型的字段(类似表的外键)…

Json简述(C++)

目录 1.介绍 2.格式 3.底层 3.1数据对象表示 3.2序列化接口 3.3反序列化接口 4.使用 1.介绍 Json&#xff08;JavaScript Object Notation&#xff09;是一种轻量级的数据交换格式&#xff0c;其最早是为JavaScript编程语言设计的格式。不过发发展至今&#xff0c;Jso…

C++——缺省参数

缺省参数的定义 缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数的时候&#xff0c;如果没有指定实参&#xff0c;则采用该形参的缺省值&#xff0c;否则使用指定的实参。 void Func(int a 0) {cout << a << endl; } int main() { Func()…

并查集的原理与实现

1.概念 2.生活中的例子 小弟-老大&#xff1b; 帮派识别 3.实现 3.1 初始化 3.2 中间过程 3.3合并 3.4 并查集路径优化 直接把下面的节点指向最终的老大。 3.5 伪代码实现 3.6JAVA实现 findRoot: 谁是帮派的老大。例如山鸡的老大是陈浩南 connected: 我们是不是同一个大…

Golang服务的请求调度

文章目录 1. 写在前面2. SheddingHandler的实现原理3. 相关方案的对比4. 小结 1. 写在前面 最近在看相关的Go服务的请求调度的时候&#xff0c;发现在gin中默认提供的中间件中&#xff0c;不含有请求调度相关的逻辑中间件&#xff0c;去github查看了一些服务框架&#xff0c;发…

软工导论知识框架(八)面向对象设计风格

一.面向对象实现 把面向对象设计结果翻译成面向对象程序测试并调试面向对象的程序 二.程序设计语言 所有语言都可完成面向对象实现&#xff0c;但效果不同。 使用非面向对象语言编写面向对象程序&#xff0c;则必须由程序员自己把面向对象概念映射到目标程序中。 1.将来能够占…

Ubuntu常用配置

文章目录 1. 安装VMware虚拟机软件2. 下载Ubuntu镜像3. 创建Ubuntu虚拟机4. 设置屏幕分辨率5. 更改系统语言为中文6. 切换中文输入法7. 修改系统时间8. 修改锁屏时间9. 通过系统自带的应用商店安装软件10. 安装JDK11. 安装 IntelliJ IDEA12. 将左侧任务栏自动隐藏13. 安装docke…