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() {                // 自定义个handlerprotected 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*/@Overridepublic 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*/@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) throws Exception {System.out.println("EchoServerHandlechannelReadComplete 从管道中读取数据完毕...");}/** 异常捕获* @param: ctx* @param: cause* @return: void*/@Overridepublic 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*/@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {System.out.println("Active 管道激活...");ctx.writeAndFlush(Unpooled.copiedBuffer("711 改了密码:",CharsetUtil.UTF_8));}/** 管道数据读取完毕* @param: ctx* @return: void*/@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) throws Exception {System.out.println("EchoClientHandlerchannelReadComplete 管道读取完毕...");}/** 异常捕获* @param: ctx* @param: cause* @return: void*/@Overridepublic 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?

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

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

相关文章

【ARM Cache 系列文章 9 -- ARM big.LITTLE技术】

文章目录 big.LITTLE 技术背景big.LITTLE 技术详解big.LITTLE 硬件要求 big.LITTLE 软件模型CPU MigrationGlobal Task SchedulingGlobal Task Scheduling比CPU Migration的优势 转自&#xff1a;https://zhuanlan.zhihu.com/p/630981648 如有侵权&#xff0c;请联系删除 big.L…

Leetcode 21. 合并两个有序链表

题目描述 题目链接&#xff1a;https://leetcode.cn/problems/merge-two-sorted-lists/description/ 思路 两个链表都是升序链表&#xff0c;新建一个链表&#xff0c;引入伪头节点作为辅助节点&#xff0c;将各节点添加到伪节点之后&#xff0c;再用一个cur节点指向新链表的…

2022年03月 C/C++(一级)真题解析#中国电子学会#全国青少年软件编程等级考试

第1题:双精度浮点数的输入输出 输入一个双精度浮点数,保留8位小数,输出这个浮点数。 时间限制:1000 内存限制:65536 输入 只有一行,一个双精度浮点数。 输出 一行,保留8位小数的浮点数。 样例输入 3.1415926535798932 样例输出 3.14159265 下面是一个使用C语言编写的双精…

51单片机学习--红外遥控(外部中断)

需要利用下面这个红外接收头&#xff0c;OUT口会发出红外信号对应的高低电平&#xff0c;由于发送的速度很快&#xff0c;所以需要把OUT引脚接在外部中断引脚上&#xff0c;当OUT一旦产生下降沿&#xff0c;马上进中断&#xff0c;这样响应会更及时。 外部中断引脚位于P3_2和P…

全球八分之一的河流受到缺氧影响

一项全球研究发现&#xff0c;世界各地河流中的溶解氧含量低得危险。缺氧的真实发生率可能更高。 小型、低梯度的城市河流&#xff0c;例如图中北卡罗来纳州的那条河流&#xff0c;是最容易缺氧的河流之一。图片来源&#xff1a;乔安娜布拉扎克 2023 年 3 月&#xff0c;《卫报…

学生管理系统(Python版本)

class Student:def __init__(self, id, name, age):self.id idself.name nameself.age ageclass StudentManagementSystem:def __init__(self):self.students []def add_student(self, student):self.students.append(student)print("学生信息添加成功&#xff01;&qu…

大脑营行|“福安市华龙教育基金”支持家乡教育事业发展

8月8日&#xff0c;福安市松罗中学举行“福安市华龙教育基金”中考奖学金颁发仪式。福安市松罗乡党委书记钟文、乡长郑仁寿、福安市人民政府教育督导室副科级督导员&#xff08;片区领导&#xff09;陈秦、校长张明亮、各村支部书记、家长代表、受奖学生&#xff0c;校领导班子…

UG NX二次开发(C#)-采用PK函数与NXOpen的效率对比

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 1、前言2、创建一个测试项目2.1 创建工程2.2 添加引用2.3 添加PK函数代码2.4 添加NXOpen.net的代码2.5 在mn函数中调用这两个方法2.6 生成dll3、测试代码3.1 在UG NX11.0中创建一个part3.2 调用tes…

vue中$bus全局事件总线

1.介绍 说明&#xff1a;Vue中&#xff0c;$bus 指的通常是一个全局事件总线&#xff0c;它是一种用于在不同组件之间进行通信的模式。它允许你在一个组件中发出事件&#xff0c;而其他组件可以监听并响应这些事件。 2.main.js 说明&#xff1a;为什么在beforeCreate钩子函数…

@RequestHeader使用

RequestHeader 请求头参数的设置 GetMapping("paramTest/requestHeader")public String requestHeaderTest(RequestHeader("name") String name){return name;} 在Postman的Headers中添加请求头参数&#xff0c;不过貌似不能加中文

实现两个列表对应数值相乘、相除、相加等

实现两个列表对应数值相乘、相除、相加等 利用循环实现两个列表相乘使用zip()方法在Python中实现两个列表相乘使用numpy.multiply()方法在Python中实现两个列表相乘使用map()函数在Python中实现两个列表相乘1、利用循环实现两个列表相乘 for循环遍历两个列表元素&#xff0c;…

基于FPGA的PID算法理论详解(1)

基于FPGA的PID算法理论详解(1) 1 概述 比例-积分-微分(PID)控制是业内最常见的控制算法,在工业控制领域有很高的接受度。PID控制器的广泛应用得益于其在多种操作条件下稳定的性能,以及易操作的特性。工程师可以用简单直观的方式实现PID控制。PID控制有三个基本要件:比…

百川智能发布首个530亿参数闭源大模型,今年追上GPT-3.5

4月官宣创业&#xff0c;6月15日发布第一款7B开源模型&#xff0c;7月11日发布第二款13B、130亿参数开源模型。 平均保持2个月一个版本发布速度&#xff0c;8月8日&#xff0c;百川智能发布了创业以来的首个530亿参数闭源大模型——Baichuan-53B&#xff08;以下简称“53B”&a…

LeetCode 热题 100 JavaScript -- 74. 搜索二维矩阵

给你一个满足下述两条属性的 m x n 整数矩阵&#xff1a; 每行中的整数从左到右按非递减顺序排列。 每行的第一个整数大于前一行的最后一个整数。 给你一个整数 target &#xff0c;如果 target 在矩阵中&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 …

无涯教程-Perl - glob函数

描述 此函数返回与EXPR匹配的文件的列表,这些文件将由标准Bourne shell进行扩展。如果EXPR未指定路径,请使用当前目录。如果省略EXPR,则使用$_的值。 从Perl 5.6开始,扩展是在内部完成的,而不是使用外部脚本。扩展遵循csh(以及任何派生形式,包括tcsh和bash)的扩展方式,其翻译…

从后往前读取列表的方法

从后往前读取列表的方法 方法1&#xff1a;使用for循环遍历列表时&#xff0c;可以使用reverse()函数将列表反转&#xff0c;然后再遍历。 # 列表 num [0, 1, 2, 3]# 反向遍历 for i in reversed(num):print(i)输出结果&#xff1a; 3 2 1 0方法2&#xff1a;先计算列表长度…

【STM32】小电流FOC驱控一体板(开源)

FOC驱控一体板http://链接: https://pan.baidu.com/s/12HoV9yDlMC5QVGNCJ5tK0w 提取码: 1111 主控芯片stm32f103c8t6 驱动芯片drv8313 三相电流采样 根据B站一个UP主的改的&#xff08;【【自制】年轻人的第一块FOC驱动器】&#xff09;&#xff0c;大多数元器件是0805&…

(第二篇)ansible-kubeadm在线安装单master集群

ansible可以安装的KS8版本如下&#xff1a; 请按照此博客中的内容操作后&#xff0c;才可以通过下面的命令查询到版本。 [rootk8s-master01 ~]# yum list kubectl --showduplicates | sort -r kubectl.x86_64 1.20.0-0 kubern…

Java SpringBoot 加载 yml 配置文件中字典项

实际项目中&#xff0c;如果将该类信息放配置文件中的话&#xff0c;一般会结合Nocas一起使用 将字典数据&#xff0c;配置在 yml 文件中&#xff0c;通过加载yml将数据加载到 Map中 Spring Boot 中 yml 配置、引用其它 yml 中的配置。# 在配置文件目录&#xff08;如&#xff…

第一百一十一回 如何实现屏幕适配

文章目录 概念介绍实现方法示例代码 我们在上一章回中介绍了动画相关的内容&#xff0c;本章回中将介绍 如何适配屏幕.闲话休提&#xff0c;让我们一起Talk Flutter吧。 概念介绍 我们平常使用的手机屏幕大小不同&#xff0c;App运行在这些大小不同的屏幕上时效果却相同&…