高阶面试-netty部分
介绍下netty
Netty 是一个基于 Java 的异步事件驱动的网络应用框架,提供了用于快速开发高性能、高可扩展性的协议服务器和客户端的工具
BIO、NIO、AIO 的区别是什么
BIO
blocking io,同步阻塞IO,比较简单,为每个请求分配一个线程处理,基于stream流
缺点:
- 性能问题 并发量大,需要创建大量线程,导致系统开销增加,性能下降
- 资源浪费 每个连接需要一个线程处理,连接空闲时,线程也占用系统资源,浪费资源
因此,jdk1.4引入了NIO
NIO
NIO基于channel和buffer的非阻塞IO
特点:
- 非阻塞 channel是双向的,可读可写,而传统的stream是单向的;设置非阻塞后,线程在没有数据可读可写时立即返回,而不是阻塞等待
- 通道和缓冲区 缓冲区提高数据的读写效率,并支持直接内存访问direct buffer,避免JVM内存和系统内存之间的复制
- 选择器selector,同时监控多个通道的IO事件,使得一个线程可以管理多个通道,减少线程的数量和上下文切换的开销
AIO
NIO的selector在做轮询的时候,如果没有事件发生,也会阻塞,如何优化?
jdk1.7引入AIO,真正异步IO,可以提交读写操作,立刻返回,无需等待,操作完成,操作系统会通知;IO操作完会回调相应的处理器,不需要线程阻塞等待。
netty的应用场景
分布式系统中的 RPC 框架网络通信工具、HTTP 服务器、即时通讯系统、消息推送系统等
你们用在什么场景?
用作服务,比如agi服务,提高通话服务的并发
netty的核心组件
包括 ByteBuf 字节容器、Bootstrap 和 ServerBootstrap 启动引导类、Channel 网络操作抽象类、EventLoop 事件循环等
channel
Netty 中用于网络 I/O 操作的基本构件,类似于传统的 Java NIO 中的 Channel。它代表了一个打开的连接,可以执行读、写、连接和绑定等操作
NioSocketChannel:基于 NIO 的 Socket 通道,实现了客户端连接。NioServerSocketChannel:基于 NIO 的服务器 Socket 通道,实现了服务器端的监听。NioDatagramChannel:基于 NIO 的 UDP 通道,用于无连接的数据报传输
EventLoop 和 EventLoopGroup
EventLoop 是一个处理所有 I/O 事件的核心抽象,负责在其生命周期内处理一个或多个 Channel 的 I/O 操作。EventLoopGroup 是一组 EventLoop,用于管理和调度多个 EventLoop。
NioEventLoopGroup:使用 NIO Selector 实现的EventLoopGroup。EpollEventLoopGroup:使用 epoll 实现的EventLoopGroup,适用于 Linux 平台。
Bootstrap 和 ServerBootstrap
Netty 提供的辅助类,用于简化客户端和服务器的启动配置
ChannelFuture
代表一个异步的 I/O 操作结果,提供了检查操作是否完成的方法,并可以注册监听器,在操作完成时得到通知。
ChannelHandler 和 ChannelPipeline
ChannelHandler 是处理 I/O 事件或拦截 I/O 操作的核心组件。ChannelPipeline 是一个处理 ChannelHandler 链的容器,负责将 I/O 事件按顺序传递给链中的各个处理器。
常见的 ChannelHandler:
ChannelInboundHandler:处理入站 I/O 事件。ChannelOutboundHandler:处理出站 I/O 操作
ByteBuf
ByteBuf 是 Netty 提供的用于数据读写的缓冲区,比 JDK 的 ByteBuffer 更加灵活和高效。它支持动态扩展和各种操作,如切片、复制和聚合
ChannelInitializer
ChannelInitializer 是一个特殊的 ChannelInboundHandler,用于在 Channel 注册到 EventLoop 后初始化 ChannelPipeline。
Reactor 线程模型
一种并发编程模型,定义了三种角色:
Reactor:负责监听和分配事件,将I/O事件分派给对应的Handler。新的事件包含连接建立就绪、读就绪、写就绪等。
Acceptor:处理客户端新连接,并分派请求到处理器链中。
Handler:将自身与事件绑定,执行非阻塞读/写任务,完成channel的读入,完成处理业务逻辑后,负责将结果写出channel
三类:
单reactor单线程
![[Pasted image 20240626220034.png]]
单reactor多线程
![[Pasted image 20240626220130.png]]
多reactor多线程:主从reactor,也称为1+M+N 线程模式,被nginx、netty、memcached等使用
MainReactor 只负责监听客户端连接请求,和客户端建立连接之后将连接交由SubReactor 监听后面的 IO 事件
![[Pasted image 20240626220154.png]]
netty的reactor实现
![[Pasted image 20240626221336.png]]
Netty 的高性能体现在哪些方面
1. 异步非阻塞 I/O (NIO)
Netty 基于 Java NIO 库构建,使用异步非阻塞 I/O 模型,有效地利用了系统资源。与传统的阻塞 I/O 模型相比,NIO 可以在同一个线程中处理多个连接,减少了线程切换和上下文切换的开销。
2. 高效的线程模型
Netty 提供了灵活的线程模型,通过事件循环 (EventLoop) 和工作线程池来处理 I/O 事件和任务。默认情况下,Netty 使用主从 Reactor 模型,主线程组处理客户端连接,工作线程组处理读写和业务逻辑。这样的设计避免了线程之间的竞争,提高了性能。
3. 零拷贝 (Zero-Copy)
Netty 使用了多种零拷贝技术来减少数据在内存中的拷贝次数,提高 I/O 效率。例如:
FileRegion用于直接将文件内容传输到网络中。- 使用
DirectBuffer直接进行 I/O 操作,而不需要将数据从用户空间复制到内核空间。
4. 内存管理
Netty 提供了高效的内存管理机制,包括 PooledByteBufAllocator 和 UnpooledByteBufAllocator。通过池化的方式来分配和管理内存,减少了频繁的内存分配和回收的开销,从而提高了性能。
5. Pipeline 和 Handler 机制
Netty 使用了责任链模式,通过 ChannelPipeline 和 ChannelHandler 来处理网络事件。每个 ChannelHandler 只关注自己的处理逻辑,避免了复杂的逻辑集中在一个地方。这样的设计不仅提高了代码的可维护性,还通过流水线方式提升了处理效率。
6. 事件驱动模型
Netty 的事件驱动模型使得它能够高效地处理网络事件。所有的 I/O 操作都是非阻塞的,通过事件通知机制来触发相应的操作,而不是通过轮询的方式。这种方式减少了不必要的系统调用和 CPU 占用。
7. 支持多种协议
Netty 支持多种协议的编解码器,可以方便地处理各种网络协议(如 HTTP, WebSocket, FTP 等)。这些编解码器经过优化,能够高效地进行协议解析和数据处理,减少了开发者自己实现的负担。
8. 高度可定制
Netty 提供了高度可定制的 API,可以根据具体应用的需求进行优化。例如,可以自定义线程池、事件循环、内存分配器等,从而在不同的场景下实现最佳性能。
拆包和粘包
使用 TCP 协议时。它们分别指数据包在传输过程中被拆分成多个小包(拆包)或者多个数据包被合并成一个大包(粘包)的现象
拆包
拆包是指一个完整的数据包在传输过程中被拆分成多个小包。例如,发送端发送了一个较大的数据包,但接收端只能接收到一部分数据,然后再接收剩下的数据。
粘包
粘包是指多个数据包在传输过程中被合并成一个大包。例如,发送端连续发送多个小数据包,但接收端在一次接收操作中接收到多个数据包的数据。
解决方案:
-
固定长度法
- 每个数据包的长度是固定的,接收端每次按照固定的长度进行读取。缺点是可能会浪费带宽,因为长度是固定的,无论实际数据量多少都要填充到固定长度。
-
特殊分隔符法
- 在数据包之间使用特殊分隔符,接收端通过分隔符来区分数据包。常见的分隔符有换行符
\n、自定义分隔符等。
- 在数据包之间使用特殊分隔符,接收端通过分隔符来区分数据包。常见的分隔符有换行符
-
包头加包体法
- 在数据包的头部增加一个固定长度的包头,包头中包含数据包的长度信息。接收端首先读取包头,根据包头中的长度信息再读取相应长度的包体
Netty 提供了多种解码器来解决粘包问题,比如固定长度解码、分隔符解码、长度字段解码等。
- 在数据包的头部增加一个固定长度的包头,包头中包含数据包的长度信息。接收端首先读取包头,根据包头中的长度信息再读取相应长度的包体
- 使用固定长度帧解码器 (FixedLengthFrameDecoder)
public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new FixedLengthFrameDecoder(20)); // 假设每个消息长度为20 ch.pipeline().addLast(new NettyServerHandler()); }
使用行分隔符解码器 (LineBasedFrameDecoder)
ch.pipeline().addLast(new LineBasedFrameDecoder(1024));// 设定最大帧长度为1024
使用定界符解码器 (DelimiterBasedFrameDecoder)
ch.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, Unpooled.wrappedBuffer(new byte[]{'|'})));
使用基于长度字段的解码器 (LengthFieldBasedFrameDecoder)
在消息头部添加一个长度字段,用于指示消息体的长度
server:
ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(1048576, 0, 4, 0, 4));client:
ch.pipeline().addLast(new LengthFieldPrepender(4));
Netty 的长连接和心跳机制是如何工作
长连接是指客户端和服务器之间建立的连接在一次创建后能够长期保持,Netty 默认使用的就是长连接模式。可以通过设置 ChannelOption.SO_KEEPALIVE 为 true 来启用 TCP 层的心跳检测,通常我们还会在应用层实现自己的心跳机制,以确保更细粒度的控制。
实现步骤
- 添加心跳处理器
- 在服务器端处理心跳请求
- 在客户端定时发送心跳请求
server:
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;public class HeartbeatServer {public static void main(String[] args) throws InterruptedException {EventLoopGroup bossGroup = new NioEventLoopGroup(1);EventLoopGroup workerGroup = new NioEventLoopGroup();try {ServerBootstrap b = new ServerBootstrap();b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_KEEPALIVE, true).handler(new LoggingHandler(LogLevel.INFO)).childHandler(new ChannelInitializer<SocketChannel>() {@Overridepublic void initChannel(SocketChannel ch) throws Exception {ch.pipeline().addLast(new IdleStateHandler(60, 0, 0)); // 60秒内没有读操作则触发IdleStateEventch.pipeline().addLast(new HeartbeatServerHandler());}});b.bind(8080).sync().channel().closeFuture().sync();} finally {bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}static class HeartbeatServerHandler extends SimpleChannelInboundHandler<Object> {@Overrideprotected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {// 处理其他消息}@Overridepublic void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {if (evt instanceof IdleStateEvent) {IdleStateEvent event = (IdleStateEvent) evt;switch (event.state()) {case READER_IDLE:System.out.println("读超时,关闭连接");ctx.close();break;default:break;}} else {super.userEventTriggered(ctx, evt);}}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {cause.printStackTrace();ctx.close();}}
}
client:
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.concurrent.ScheduledFuture;import java.util.concurrent.TimeUnit;public class HeartbeatClient {public static void main(String[] args) throws InterruptedException {EventLoopGroup group = new NioEventLoopGroup();try {Bootstrap b = new Bootstrap();b.group(group).channel(NioSocketChannel.class).option(ChannelOption.SO_KEEPALIVE, true).handler(new ChannelInitializer<SocketChannel>() {@Overridepublic void initChannel(SocketChannel ch) throws Exception {ch.pipeline().addLast(new IdleStateHandler(0, 30, 0)); // 30秒内没有写操作则触发IdleStateEventch.pipeline().addLast(new HeartbeatClientHandler());}});ChannelFuture f = b.connect("localhost", 8080).sync();f.channel().closeFuture().sync();} finally {group.shutdownGracefully();}}static class HeartbeatClientHandler extends SimpleChannelInboundHandler<Object> {private ScheduledFuture<?> heartBeat;@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {heartBeat = ctx.executor().scheduleAtFixedRate(() -> {ctx.writeAndFlush("HEARTBEAT");System.out.println("发送心跳");}, 0, 30, TimeUnit.SECONDS);}@Overrideprotected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {// 处理服务器响应}@Overridepublic void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {if (evt instanceof IdleStateEvent) {IdleStateEvent event = (IdleStateEvent) evt;switch (event.state()) {case WRITER_IDLE:System.out.println("写超时,发送心跳");ctx.writeAndFlush("HEARTBEAT");break;default:break;}} else {super.userEventTriggered(ctx, evt);}}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {cause.printStackTrace();ctx.close();}@Overridepublic void channelInactive(ChannelHandlerContext ctx) throws Exception {if (heartBeat != null) {heartBeat.cancel(false);}}}
}
Netty 支持哪些序列化协议
Netty 支持多种序列化协议,用于不同场景下的数据传输需求。以下是一些常见的序列化协议及其在 Netty 中的实现方式:
1. Java 序列化
Java 序列化使用 Java 内置的 ObjectOutputStream 和 ObjectInputStream,可以将 Java 对象转换为字节流。
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;// 服务端
ch.pipeline().addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(null)));
ch.pipeline().addLast(new ObjectEncoder());// 客户端
ch.pipeline().addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(null)));
ch.pipeline().addLast(new ObjectEncoder());
2. JSON 序列化
JSON 序列化使用文本格式,易于阅读和调试。可以使用 Jackson 或 Gson 进行 JSON 序列化。
使用 Jackson
import com.fasterxml.jackson.databind.ObjectMapper;
import io.netty.handler.codec.json.JsonObjectDecoder;
import io.netty.handler.codec.MessageToMessageDecoder;
import io.netty.handler.codec.MessageToMessageEncoder;public class JsonEncoder extends MessageToMessageEncoder<Object> {private final ObjectMapper objectMapper = new ObjectMapper();@Overrideprotected void encode(ChannelHandlerContext ctx, Object msg, List<Object> out) throws Exception {byte[] bytes = objectMapper.writeValueAsBytes(msg);out.add(Unpooled.wrappedBuffer(bytes));}
}public class JsonDecoder extends MessageToMessageDecoder<ByteBuf> {private final ObjectMapper objectMapper = new ObjectMapper();private final Class<?> clazz;public JsonDecoder(Class<?> clazz) {this.clazz = clazz;}@Overrideprotected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {byte[] bytes = new byte[msg.readableBytes()];msg.readBytes(bytes);Object obj = objectMapper.readValue(bytes, clazz);out.add(obj);}
}// 服务端和客户端
ch.pipeline().addLast(new JsonObjectDecoder());
ch.pipeline().addLast(new JsonDecoder(MyClass.class));
ch.pipeline().addLast(new JsonEncoder());
3. Protobuf 序列化
Protobuf(Protocol Buffers)是 Google 开发的一种高效的二进制序列化协议,适用于高性能场景。
import io.netty.handler.codec.protobuf.ProtobufDecoder;
import io.netty.handler.codec.protobuf.ProtobufEncoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;// 服务端和客户端
ch.pipeline().addLast(new ProtobufVarint32FrameDecoder());
ch.pipeline().addLast(new ProtobufDecoder(MyProtoClass.getDefaultInstance()));
ch.pipeline().addLast(new ProtobufVarint32LengthFieldPrepender());
ch.pipeline().addLast(new ProtobufEncoder());
5. Kryo 序列化
Kryo 是一个快速、高效的对象图序列化框架,适用于需要高性能序列化的 Java 应用
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import io.netty.handler.codec.MessageToByteEncoder;
import io.netty.handler.codec.ByteToMessageDecoder;// 自定义 Kryo 解码器和编码器
public class KryoEncoder extends MessageToByteEncoder<Object> {private final Kryo kryo = new Kryo();@Overrideprotected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out) throws Exception {ByteArrayOutputStream baos = new ByteArrayOutputStream();Output output = new Output(baos);kryo.writeClassAndObject(output, msg);output.close();out.writeBytes(baos.toByteArray());}
}public class KryoDecoder extends ByteToMessageDecoder {private final Kryo kryo = new Kryo();@Overrideprotected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {byte[] bytes = new byte[in.readableBytes()];in.readBytes(bytes);Input input = new Input(new ByteArrayInputStream(bytes));Object obj = kryo.readClassAndObject(input);out.add(obj);}
}// 服务端和客户端
ch.pipeline().addLast(new KryoEncoder());
ch.pipeline().addLast(new KryoDecoder());
bytebuf相对butebuffer的优点
1. 更丰富的 API
- 读写索引分离:
ByteBuf将读索引和写索引分离,提供了readerIndex和writerIndex,而ByteBuffer只有一个位置指针,通过flip和clear方法来切换读写模式。 - 链式调用:
ByteBuf的大多数方法都返回this,允许链式调用,使代码更加简洁和流畅
2. 容量和动态扩展
- 容量管理:
ByteBuf支持动态扩展容量,而ByteBuffer的容量是固定的,一旦分配不能改变。 - 容量检查:
ByteBuf提供了多种方法来检查可读字节数和可写字节数,如readableBytes()和writableBytes(),可以避免越界错误。
3. 内存管理
- 池化机制:
ByteBuf支持池化,可以重用缓冲区,减少内存分配和垃圾回收的开销。Netty 的PooledByteBufAllocator是一个高效的内存池实现,而ByteBuffer只能依赖 JVM 的垃圾回收。 - 零拷贝:
ByteBuf支持零拷贝操作,如slice()、duplicate()和composite buffer,减少数据拷贝,提高性能。
4. 引用计数和生命周期管理
- 引用计数:
ByteBuf使用引用计数来管理其生命周期,通过retain()和release()方法可以精细控制内存的释放。而ByteBuffer只能依赖垃圾回收,无法手动管理内存的释放。
5. 更灵活的缓冲区类型
- 堆内缓冲区和直接缓冲区:
ByteBuf支持堆内缓冲区(heap buffer)和直接缓冲区(direct buffer),可以根据需要选择合适的类型。而ByteBuffer需要通过ByteBuffer.allocate()和ByteBuffer.allocateDirect()分别创建。 - 复合缓冲区:
ByteBuf提供了CompositeByteBuf,允许多个缓冲区组合成一个逻辑缓冲区,避免数据复制。
相关文章:
高阶面试-netty部分
介绍下netty Netty 是一个基于 Java 的异步事件驱动的网络应用框架,提供了用于快速开发高性能、高可扩展性的协议服务器和客户端的工具 BIO、NIO、AIO 的区别是什么 BIO blocking io,同步阻塞IO,比较简单,为每个请求分配一个线…...
在 C++的跨平台开发中,如何处理不同操作系统和编译器之间的细微差异,以确保程序能够稳定且高效地运行?
在 C 的跨平台开发中,处理不同操作系统和编译器之间的细微差异是非常重要的。以下是一些处理差异的技巧: 使用条件编译:使用预处理指令,根据不同的操作系统和编译器来编写不同的代码。 #if defined(_WIN32)// Windows 特定代码 …...
独孤思维:脑子不好使,副业稳赚钱
01 副业,贴身级模仿。 比如独孤最近在测试dy虚拟资料项目。 跑了三个多月。 赚了点下小钱。 从最开始的自动生成视频,到后来的抽帧优化,再到先做的矩阵玩法。 一直都在迭代。 是独孤脑子好使吗? 恰恰相反。 正式因为独孤…...
【数据结构】(C语言):二叉搜索树
二叉搜索树: 树不是线性的,是层级结构。基本单位是节点,每个节点最多2个子节点。有序。每个节点,其左子节点都比它小,其右子节点都比它大。每个子树都是一个二叉搜索树。每个节点及其所有子节点形成子树。可以是空树。…...
泛微开发修炼之旅--23基于ecology自研的数据库分页组件(分页组件支持mysql、sqlserver、oracle、达梦等)
一、使用场景 ecology二开开发过程中,经常要使用到分页查询,随着信创项目的到来,各种国产数据库的出现,对于数据库分页查询兼容何种数据库,就迫在眉睫。 于是,我自己基于ecology开发了一个分页插件&#…...
《昇思25天学习打卡营第4天 | mindspore Transforms 数据变换常见用法》
1. 背景: 使用 mindspore 学习神经网络,打卡第四天; 2. 训练的内容: 使用 mindspore 的常见的数据变换 Transforms 的使用方法; 3. 常见的用法小节: 支持一系列常用的 Transforms 的操作 3.1 Vision …...
【Python时序预测系列】基于LSTM实现多输入多输出单步预测(案例+源码)
这是我的第312篇原创文章。 一、引言 单站点多变量输入多变量输出单步预测问题----基于LSTM实现。 多输入就是输入多个特征变量 多输出就是同时预测出多个标签的结果 单步就是利用过去N天预测未来1天的结果 二、实现过程 2.1 读取数据集 dfpd.read_csv("data.csv&qu…...
git客户端工具之Github,适用于windows和mac
对于我本人,我已经习惯了使用Github Desktop,不同的公司使用的代码管理平台不一样,就好奇Github Desktop是不是也适用于其他平台,结果是可以的。 一、克隆代码 File --> Clone repository… 选择第三种URL方式,输入url &…...
ai除安卓手机版APP软件一键操作自动渲染去擦消稀缺资源下载
安卓手机版:点击下载 苹果手机版:点击下载 电脑版(支持Mac和Windows):点击下载 一款全新的AI除安卓手机版APP,一键操作,轻松实现自动渲染和去擦消效果,稀缺资源下载 1、一键操作&…...
Unity获取剪切板内容粘贴板图片文件文字
最近做了一个发送消息的unity项目,需要访问剪切板里面的图片文字文件等,翻遍了网上的东西,看了不是需要导入System.Windows.Forms(关键导入了unity还不好用,只能用在纯c#项目中),所以我看了下py…...
利用谷歌云serverless代码托管服务Cloud Functions构建Gemini Pro API
谷歌在2024年4月发布了全新一代的多模态模型Gemini 1.5 Pro,Gemini 1.5 Pro不仅能够生成创意文本和代码,还能理解、总结上传的图片、视频和音频内容,并且支持高达100万tokens的上下文。在多个基准测试中表现优异,性能超越了ChatGP…...
极狐GitLab 17.0 重磅发布,100+ DevSecOps功能更新来啦~【一】
GitLab 是一个全球知名的一体化 DevOps 平台,很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab :https://gitlab.cn/install?channelcontent&utm_sourcecsdn 是 GitLab 在中国的发行版,专门为中国程序员服务。可以一键式部署…...
python实现符文加、解密
在历史悠久的加密技术中,恺撒密码以其简单却有效的原理闻名。通过固定的字母位移,明文可以被转换成密文,而解密则是逆向操作。这种技术不仅适用于英文字母,还可以扩展到其他语言的字符体系,如日语的平假名或汉语的拼音…...
【解释】i.MX6ULL_IO_电气属性说明
【解释】i.MX6ULL_IO_电气属性说明 文章目录 1 Hyst1.1 迟滞(Hysteresis)是什么?1.2 GPIO的Hyst. Enable Field 参数1.3 应用场景 2 Pull / Keep Select Field2.1 PUE_0_Keeper — Keeper2.2 PUE_1_Pull — Pull2.3 选择Keeper还是Pull 3 Dr…...
02-《石莲》
石 莲 石莲(学名:Sinocrassula indica A.Berger),别名因地卡,为二年生草本植物,全株无毛,具须根。花茎高15-60厘米,直立,常被微乳头状突起。茎生叶互生,宽倒披…...
MySQL之聚簇索引和非聚簇索引
1、什么是聚簇索引和非聚簇索引? 聚簇索引,通常也叫聚集索引。 非聚簇索引,指的是二级索引。 下面看一下它们的含义: 1.1、聚集索引选取规则 如果存在主键,主键索引就是聚集索引。如果不存在主键,将使…...
Web后端开发之前后端交互
http协议 http ● 超文本传输协议 (HyperText Transfer Protocol)服务器传输超文本到本地浏览器的传送协议 是互联网上应用最为流行的一种网络协议,用于定义客户端浏览器和服务器之间交换数据的过程。 HTTP是一个基于TCP/IP通信协议来传递数据. HTT…...
520. 检测大写字母 Easy
我们定义,在以下情况时,单词的大写用法是正确的: 全部字母都是大写,比如 "USA" 。 单词中所有字母都不是大写,比如 "leetcode" 。 如果单词不只含有一个字母,只有首字母大写࿰…...
vue的跳转传参
1、接收参数使用route,route包含路由信息,接收参数有两种方式,params和query path跳转只能使用query传参,name跳转都可以 params:获取来自动态路由的参数 query:获取来自search部分的参数 写法 path跳,query传 传参数 import { useRout…...
docker配置镜像源
1)打开 docker配置文件 sudo nano /etc/docker/daemon.json 2)添加 国内镜像源 {"registry-mirrors": ["https://akchsmlh.mirror.aliyuncs.com","https://registry.docker-cn.com","https://docker.mirrors.ustc…...
[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解
突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 安全措施依赖问题 GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...
CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型
CVPR 2025 | MIMO:支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题:MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者:Yanyuan Chen, Dexuan Xu, Yu Hu…...
【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...
【2025年】解决Burpsuite抓不到https包的问题
环境:windows11 burpsuite:2025.5 在抓取https网站时,burpsuite抓取不到https数据包,只显示: 解决该问题只需如下三个步骤: 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...
微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...
leetcodeSQL解题:3564. 季节性销售分析
leetcodeSQL解题:3564. 季节性销售分析 题目: 表:sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...
OPENCV形态学基础之二腐蚀
一.腐蚀的原理 (图1) 数学表达式:dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一,腐蚀跟膨胀属于反向操作,膨胀是把图像图像变大,而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...
算法笔记2
1.字符串拼接最好用StringBuilder,不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问(基础概念问题) 1. 请解释Spring框架的核心容器是什么?它在Spring中起到什么作用? Spring框架的核心容器是IoC容器&#…...
C++:多态机制详解
目录 一. 多态的概念 1.静态多态(编译时多态) 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1).协变 2).析构函数的重写 5.override 和 final关键字 1&#…...
