高阶面试-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 通道,用于无连接的数据报传输

EventLoopEventLoopGroup

EventLoop 是一个处理所有 I/O 事件的核心抽象,负责在其生命周期内处理一个或多个 Channel 的 I/O 操作。EventLoopGroup 是一组 EventLoop,用于管理和调度多个 EventLoop

  • NioEventLoopGroup:使用 NIO Selector 实现的 EventLoopGroup
  • EpollEventLoopGroup:使用 epoll 实现的 EventLoopGroup,适用于 Linux 平台。

BootstrapServerBootstrap

Netty 提供的辅助类,用于简化客户端和服务器的启动配置

ChannelFuture

代表一个异步的 I/O 操作结果,提供了检查操作是否完成的方法,并可以注册监听器,在操作完成时得到通知。

ChannelHandlerChannelPipeline

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 提供了高效的内存管理机制,包括 PooledByteBufAllocatorUnpooledByteBufAllocator。通过池化的方式来分配和管理内存,减少了频繁的内存分配和回收的开销,从而提高了性能。

5. Pipeline 和 Handler 机制

Netty 使用了责任链模式,通过 ChannelPipelineChannelHandler 来处理网络事件。每个 ChannelHandler 只关注自己的处理逻辑,避免了复杂的逻辑集中在一个地方。这样的设计不仅提高了代码的可维护性,还通过流水线方式提升了处理效率。

6. 事件驱动模型

Netty 的事件驱动模型使得它能够高效地处理网络事件。所有的 I/O 操作都是非阻塞的,通过事件通知机制来触发相应的操作,而不是通过轮询的方式。这种方式减少了不必要的系统调用和 CPU 占用。

7. 支持多种协议

Netty 支持多种协议的编解码器,可以方便地处理各种网络协议(如 HTTP, WebSocket, FTP 等)。这些编解码器经过优化,能够高效地进行协议解析和数据处理,减少了开发者自己实现的负担。

8. 高度可定制

Netty 提供了高度可定制的 API,可以根据具体应用的需求进行优化。例如,可以自定义线程池、事件循环、内存分配器等,从而在不同的场景下实现最佳性能。

拆包和粘包

使用 TCP 协议时。它们分别指数据包在传输过程中被拆分成多个小包(拆包)或者多个数据包被合并成一个大包(粘包)的现象

拆包

拆包是指一个完整的数据包在传输过程中被拆分成多个小包。例如,发送端发送了一个较大的数据包,但接收端只能接收到一部分数据,然后再接收剩下的数据。

粘包

粘包是指多个数据包在传输过程中被合并成一个大包。例如,发送端连续发送多个小数据包,但接收端在一次接收操作中接收到多个数据包的数据。

解决方案:

  • 固定长度法

    • 每个数据包的长度是固定的,接收端每次按照固定的长度进行读取。缺点是可能会浪费带宽,因为长度是固定的,无论实际数据量多少都要填充到固定长度。
  • 特殊分隔符法

    • 在数据包之间使用特殊分隔符,接收端通过分隔符来区分数据包。常见的分隔符有换行符 \n、自定义分隔符等。
  • 包头加包体法

    • 在数据包的头部增加一个固定长度的包头,包头中包含数据包的长度信息。接收端首先读取包头,根据包头中的长度信息再读取相应长度的包体
      Netty 提供了多种解码器来解决粘包问题,比如固定长度解码、分隔符解码、长度字段解码等。
  1. 使用固定长度帧解码器 (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_KEEPALIVEtrue 来启用 TCP 层的心跳检测,通常我们还会在应用层实现自己的心跳机制,以确保更细粒度的控制。

实现步骤
  1. 添加心跳处理器
  2. 在服务器端处理心跳请求
  3. 在客户端定时发送心跳请求

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 内置的 ObjectOutputStreamObjectInputStream,可以将 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 将读索引和写索引分离,提供了 readerIndexwriterIndex,而 ByteBuffer 只有一个位置指针,通过 flipclear 方法来切换读写模式。
  • 链式调用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,允许多个缓冲区组合成一个逻辑缓冲区,避免数据复制。

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

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

相关文章

VSCode中常用的快捷键

通用操作快捷键 显示命令面板&#xff1a;Ctrl Shift P or F1&#xff0c;用于快速访问VSCode的各种命令。 快速打开&#xff1a;Ctrl P&#xff0c;可以快速打开文件、跳转到某个行号或搜索项目内容。 新建窗口/实例&#xff1a;Ctrl Shift N&#xff0c;用于打开一个新的…

三维家:SaaS的IT规模化降本之道|OceanBase 《DB大咖说》(十一)

OceanBase《DB大咖说》第 11 期&#xff0c;我们邀请到了三维家的技术总监庄建超&#xff0c;来分享他对数据库技术的理解&#xff0c;以及典型 SaaS 场景在数据库如何实现规模化降本的经验与体会。 庄建超&#xff0c;身为三维家的技术总监&#xff0c;独挑大梁&#xff0c;负…

grpc学习golang版( 八、双向流示例 )

系列文章目录 第一章 grpc基本概念与安装 第二章 grpc入门示例 第三章 proto文件数据类型 第四章 多服务示例 第五章 多proto文件示例 第六章 服务器流式传输 第七章 客户端流式传输 第八章 双向流示例 文章目录 一、前言二、定义proto文件三、编写server服务端四、编写client客…

实现高性能、可扩展的实时数据采集系统:go-zero的应用与实践

随着互联网技术的高速发展&#xff0c;数据采集也越来越受到重视&#xff0c;成为企业获取商业价值的重要手段。在实际应用中&#xff0c;我们往往面临着数据量大、并发高、系统响应速度要求高、压力测试等挑战。如何实现高性能、可扩展的实时数据采集系统&#xff1f;本文将介…

中霖教育:环评工程师好考吗?

【中霖教育好吗】【中霖教育怎么样】 在专业领域&#xff0c;环评工程师资格认证考试是一项具有挑战性的考试&#xff0c;考试科目为&#xff1a;《环境影响评价相关法律法规》 《环境影响评价技术导则与标准》《环境影响评价案例分析》《环境影响评价技术方法》。 四个科目…

【Linux】—VMware安装Centos7步骤

文章目录 前言一、虚拟机准备二、CentOS7操作系统安装 前言 本文介绍VMware安装Centos7步骤。 软件准备 软件&#xff1a;VMware Workstation Pro&#xff0c;直接官网安装。镜像&#xff1a;CentOS7&#xff0c;镜像官网下载链接&#xff1a;https://vault.centos.org/&#x…

[C++]——同步异步日志系统(1)

同步异步日志系统 一、项⽬介绍二、开发环境三、核心技术四、环境搭建五、日志系统介绍5.1 为什么需要日志系统5.2 日志系统技术实现5.2.1 同步写日志5.2.2 异步写日志 日志系统&#xff1a; 日志&#xff1a;程序在运行过程中&#xff0c;用来记录程序运行状态信息。 作用&…

Leetcode 538:把二叉搜索树转化为累加树

给出二叉 搜索 树的根节点&#xff0c;该树的节点值各不相同&#xff0c;请你将其转换为累加树&#xff08;Greater Sum Tree&#xff09;&#xff0c;使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。 解题思路&#xff1a; 其实就是相当于反中序遍历&#…

【面试系列】机器学习工程师高频面试题及详细解答

欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;欢迎订阅相关专栏&#xff1a; ⭐️ 全网最全IT互联网公司面试宝典&#xff1a;收集整理全网各大IT互联网公司技术、项目、HR面试真题. ⭐️ AIGC时代的创新与未来&#xff1a;详细讲解AIGC的概念、核心技术、…

JSONpath语法怎么用?

JSONPath 可以看作定位目标对象位置的语言&#xff0c;适用于 JSON 文档。 JSONPath 与 JSON 的 关系相当于 XPath 与 XML 的关系&#xff0c; JSONPath 参照 XPath 的路径表达式&#xff0c;提供了描述 JSON 文档层次结构的表达式&#xff0c;通过表达式对目标…

红酒与露营:户外时光的好伴侣

在繁忙的都市生活中&#xff0c;人们总是渴望逃离喧嚣&#xff0c;寻找一处宁静的天地&#xff0c;与大自然亲密相拥。露营&#xff0c;作为一种返璞归真的户外生活方式&#xff0c;成为了许多人心中的理想选择。而在露营的浪漫时光里&#xff0c;一瓶雷盛红酒的陪伴&#xff0…

AI图生视频工具测试

环境&#xff1a; 即梦 pika LUMA 可灵 问题描述&#xff1a; AI图生视频工具测试下面是原图 解决方案&#xff1a; 1.即梦 效果 2.pika 生成效果 3.LUMA 生成效果还行 4.可灵 生成效果最好

nginx 只有图片等静态资源时 监听80端口 会404 NOT FOUND

解决方法 删除 /var/nginx/sites-enabled 原因&#xff1a;当nginx没有设置首页路径index时&#xff0c;sites-enabled目录中配置的优先级会高于nginx.conf 导致404 NOT FOUND sites-enabled文件中的default会将80端口索引至默认值&#xff1a;/var/www/html目录下&#xff…

[方法] 为Cinemachine添加碰撞器

选中场景中的Cinemachine物体&#xff0c;在 Inspector 面板的最下方单击 Add Extension 下拉框&#xff0c;选择 CinemachineCollider。 之后在添加的碰撞器组件中选择要与之碰撞的层&#xff08;Collide Against&#xff09;和忽略的层&#xff08;Transparent Layers&#x…

crewAI实践过程中,memory规避openai的使用方法以及(windows下xinferece框架使用踩过的坑)

问题&#xff1a; 在使用crewAI开发项目的过程中&#xff0c;memory开启后报错&#xff1a;openai key is fake 经代码核查&#xff0c;其默认使用了openai的embedding模型。 解决方法 经查阅资料&#xff0c;可以参考其本地部署llm的方法。 本地部署模型可以使用xinference…

高薪程序员必修课-java为什么要用并发编程

目录 前言 1. 提高性能和效率 2. 更好地响应用户 3. 优化I/O操作 具体示例 示例1&#xff1a;提高性能和效率 示例2&#xff1a;更好地响应用户 示例3&#xff1a;优化I/O操作 总结 前言 并发编程允许多个线程在同一时间执行任务。下面我们从多个原理角度来解释为什么J…

【windows】亲测-win11系统跳过联网和微软账户登录,实现本地账户登录

问题原因&#xff1a;现在市面上销售的品牌笔记本和台式机基本上都预装了正版的Windows S11家族中文版操作系统&#xff0c;联网后系统会自动激活。在win11的版本中&#xff0c;隐藏了关闭跳过连接网络的按钮&#xff0c;默认强制需要注册微软账户登录才能正常使用。 一、跳过…

modify filename

import osdef add_prefix_to_filenames(directory, prefix):# 获取目录中的所有文件名for filename in os.listdir(directory):# 构建旧文件路径old_file_path os.path.join(directory, filename)# 检查是否是文件if os.path.isfile(old_file_path):# 构建新文件名new_filenam…

PyTorch中matmul函数的矩阵相乘原则和注意事项

PyTorch中matmul函数的矩阵相乘原则和注意事项 一、高维张量乘法规则 1. 选择乘法的维度&#xff1a; 选择最后两个维度进行乘 2. 维度匹配规则&#xff1a; 最后两个维度按照普通矩阵乘法计算 3. 广播机制&#xff1a;torch.matmul 函数支持广播机制&#xff0c;即在满足乘法…

springweb添加traceId

上面要求添加 traceId&#xff0c;需求很简单。 唯一的难点是&#xff0c;jakarta.servlet.http.HttpServletRequest 不支持直接 put 请求头。 所以需要创建一个可修改的对象&#xff0c;包装请求。 另外&#xff0c;由于我们应用还使用了 openFeign ,需要将 traceId 传递进去。…