提升你的Netty服务器性能:零拷贝与Reactor模型精讲

1.深入Netty的核心原理

1.1 Netty架构概览

Netty是目前使用广泛的Java NIO客户端服务器框架,它能够快速构建可维护的高性能协议服务器与客户端。起初,它由JBoss提供,现完全成为社区驱动的项目。Netty提供了一种异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。
下面是Netty的基本组成:

  • Channel:表示一个开放的连接,能进行读写操作。
  • Callbacks:回调方法,用于通知应用程序的状态改变或者操作完成。
  • Futures/Promises:Netty中用于异步操作的结果占位符。
  • Events:事件对象,用于在Netty运行时候通过EventLoop传递状态改变、操作完成等事件。
public class NettyServer {public static void main(String[] args) throws Exception {EventLoopGroup bossGroup = new NioEventLoopGroup(1);EventLoopGroup workerGroup = new NioEventLoopGroup();try {ServerBootstrap b = new ServerBootstrap();b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {@Overridepublic void initChannel(SocketChannel ch) throws Exception {ch.pipeline().addLast(new RequestDataDecoder(), new ResponseDataEncoder(), new ProcessingHandler());}}).option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, true);ChannelFuture f = b.bind(8080).sync();f.channel().closeFuture().sync();} finally {workerGroup.shutdownGracefully();bossGroup.shutdownGracefully();}}
}

1.2 事件驱动模型

事件驱动模型是Netty性能高的关键之一。这种模型允许处理事件的方式既高效又不阻塞,因此可以处理数百万级的并发连接。Netty通过定义一系列事件和对应处理器,当事件发生时,对应的处理器就会执行,从而实现非阻塞的高并发处理。

1.3 高性能IO原理剖析

Netty的高性能主要来自于其使用的是基于选择器的非阻塞IO。在Netty的设计中,它通过使用一组不同的选择器(Selector)来避免每个请求都创建一个线程,这样不仅显著减少线程数量,同时也降低上下文切换的开销,从而实现了较低的延迟和高吞吐量。
下面是一段基于Java NIO Selector机制的代码示例,它展示了如何使用Selector来管理网络连接。

import java.nio.ByteBuffer;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.util.Iterator;
import java.util.Set;
public class NioServerExample {public static void main(String[] args) throws IOException {// 创建Selector和ChannelSelector selector = Selector.open();ServerSocketChannel serverSocket = ServerSocketChannel.open();serverSocket.bind(new InetSocketAddress("localhost", 8080));serverSocket.configureBlocking(false);serverSocket.register(selector, SelectionKey.OP_ACCEPT);ByteBuffer buffer = ByteBuffer.allocate(256);while (true) {selector.select();Set<SelectionKey> selectedKeys = selector.selectedKeys();Iterator<SelectionKey> iter = selectedKeys.iterator();while (iter.hasNext()) {SelectionKey key = iter.next();// 检测到新的接入请求if (key.isAcceptable()) {register(selector, serverSocket);}// 读取客户端发送的数据if (key.isReadable()) {answerWithEcho(buffer, key);}iter.remove();}}}private static void register(Selector selector, ServerSocketChannel serverSocket) throws IOException {SocketChannel client = serverSocket.accept();client.configureBlocking(false);client.register(selector, SelectionKey.OP_READ); // 注册读取操作到选择器}private static void answerWithEcho(ByteBuffer buffer, SelectionKey key) throws IOException {SocketChannel client = (SocketChannel) key.channel();client.read(buffer);if (new String(buffer.array()).trim().equals("bye")) {client.close();System.out.println("Not accepting client messages anymore");} else {buffer.flip();client.write(buffer);buffer.clear();}}
}

这个服务器示例使用Java NIO组件构建。首先,它打开了一个ServerSocketChannel并与本地端口8080绑定,同时确保非阻塞模式被激活。之后将这个ServerSocketChannel注册到Selector中,表示对新接入的连接感兴趣。服务器进入一个死循环,持续监测是否有新事件发生。如果有新的客户端连接接入,则将其注册到Selector。如果有可读事件发生,则调用answerWithEcho`方法,将接收到的数据回写给客户端。这种方式确保了服务器能以非常低的资源利用率高效地处理数千个客户端连接。

2.Netty的高性能特性

2.1 异步非阻塞通信(NIO)

2.1.1 NIO与传统IO模型对比

在传统的IO模型中,每个连接创建时都需要对应一个线程去处理,当连接数量增加时,线程数量也会线性增加,这种模型不仅有线程上下文切换的开销,且由于线程占用的内存较多,可承载的并发连接数量受限。相比之下,NIO(Non-blocking IO)模型基于事件驱动,一个线程可以管理多个输入和输出的通道,通过Selector监控这些通道的IO事件,并进行相应的处理,从而减少了资源消耗,提高了系统的扩展性。

// Java NIO示例代码,展示基于Selector的通道监听
Selector selector = Selector.open();
channel.configureBlocking(false);
SelectionKey key = channel.register(selector, SelectionKey.OP_READ);
while(true) {int readyChannels = selector.select();if (readyChannels == 0) continue;Set<SelectionKey> selectedKeys = selector.selectedKeys();Iterator<SelectionKey> keyIterator = selectedKeys.iterator();while(keyIterator.hasNext()) {SelectionKey key = keyIterator.next();if(key.isAcceptable()) {// a connection was accepted by a ServerSocketChannel.} else if(key.isConnectable()) {// a connection was established with a remote server.} else if(key.isReadable()) {// a channel is ready for reading} else if(key.isWritable()) {// a channel is ready for writing}keyIterator.remove();}
}

2.1.2 Netty中的异步模式实现

Netty内部采用了更为高级的异步模式,不仅支持NIO提供的基本操作,还提供了Future和Promise等抽象,使得异步操作的结果可以通过监听回调的方式进行处理,同时提供了丰富的API简化开发工作。这降低了开发难度、提高了开发效率,同时也保持了NIO的高性能特点。

2.2 多路复用技术

多路复用技术是高性能网络编程的核心,它允许一个网络线程管理多个网络连接。在Netty中,这是通过Selector实现的,Selector可以监视多个通道的IO事件,如接受新的网络连接、数据读写等。

2.2.1 多路复用通讯模式解析

多路复用通讯模式通过Selector来监管每个连接上可能发生的IO事件,并在事件发生时快速响应。当任何一个注册到Selector上的Channel发生IO操作时,Selector就能检测到,并允许单个线程顺序处理这些事件,从而提高了效率,减少了资源消耗。

2.2.2 在Netty中应用多路复用

在Netty中,通过将SocketChannel注册到EventLoop的Selector上,可以实现高效的多路复用。这样,一个EventLoop就可以管理成百上千个Channel,从而显著降低了线程数目和上下文切换带来的系统开销。
以下是一段示意代码,展示了如何在Netty中注册和使用Selector进行多路复用:

public class MultiplexingServer {public static void main(String[] args) throws Exception {EventLoopGroup bossGroup = new NioEventLoopGroup(1);EventLoopGroup workerGroup = new NioEventLoopGroup();try {ServerBootstrap b = new ServerBootstrap();b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) {ch.pipeline().addLast(new MultiplexingHandler());}});ChannelFuture f = b.bind(new InetSocketAddress(8080)).sync();f.channel().closeFuture().sync();} finally {workerGroup.shutdownGracefully();bossGroup.shutdownGracefully();}}private static class MultiplexingHandler extends ChannelInboundHandlerAdapter {@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {// 处理接收到的数据...}}
}

这里,ServerBootstrap 负责配置服务器,将Channel指定给EventLoopGroup,然后通过EventLoop的Selector来管理所有的网络事件。NioEventLoopGroup 包含了一个或多个EventLoop,每个都包含自己的Selector,并能够处理多个连接上的事件,从而实现了多路复用。

2.3 零拷贝技术的应用

2.3.2 DIRECT BUFFERS在Netty中的使用

Netty利用了Java NIO中的Direct Buffer来实现零拷贝。Direct Buffer使用的是堆外直接内存,避免了在JVM堆和操作系统之间来回拷贝数据。通过使用Direct Buffer,数据可以直接在Netty的自定义缓冲区和Channel之间传输,无需额外的拷贝过程。
对于直接内存的使用,Netty提供了ByteBuf接口的不同实现,既有基于堆内存的实现,也有基于直接内存的实现。在高吞吐量的场景下,推荐使用基于堆外直接内存的DirectByteBuf,因为它能显著减少垃圾收集的压力,并且避免了数据的多次复制。

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
public class DirectBufferExample {public static void main(String[] args) {// 创建一个直接内存缓冲区ByteBuf directBuf = Unpooled.directBuffer(1024);// 检查ByteBuf是否是直接内存缓冲区if (directBuf.hasMemoryAddress()) {System.out.println("Using direct memory.");} else {System.out.println("Not using direct memory.");}// 写入数据到缓冲区directBuf.writeBytes("Hello, Netty with Zero-Copy!".getBytes());// 做一些其他与directBuf相关的操作...// 释放直接内存缓冲区directBuf.release();}
}

这段代码展示了如何在Netty中创建一个直接内存缓冲区,以及如何进行基本的操作。重点在于使用Unpooled.directBuffer()方法实例化,然后是如何进行资源的正确释放。
Netty的这种设计非常适合需要处理大量网络IO操作的应用程序,因为它可以减少Java垃圾回收的频率,并提高整体的IO效率。

2.4 基于内存池的缓冲区重用

2.4.1 内存池技术简介

内存池技术允许系统重复使用一块预先分配的内存空间,避免了频繁的内存申请和回收,这样可以显著降低因内存分配导致的性能瓶颈。Netty通过PooledByteBufAllocator实现了内存池,可以减少GC压力,增强系统稳定性。

2.4.2 Netty中内存池的高效实践

在Netty应用中,通过使用内存池,开发者可以获得池化的ByteBuf,其内部通过维护一个ByteBuf的池来重用缓冲区,减少了对象创建的成本。使用内存池的最大好处在于可以大量减少GC操作,这对于需要处理高并发请求的服务来说至关重要。

EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {ServerBootstrap b = new ServerBootstrap();b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {@Overridepublic void initChannel(SocketChannel ch) {ChannelPipeline p = ch.pipeline();p.addLast(new PooledByteBufAllocator());// 其他处理器...}});// 绑定端口并启动服务器b.bind(port).sync().channel().closeFuture().sync();
} finally {bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();
}

这段代码展示了如何在Netty中启用内存池分配器。通过在Channel初始化器中加入PooledByteBufAllocator,我们告诉Netty为此Channel使用内存池。

2.5 Reactor线程模型优化

Netty的一个关键性能特性是其使用的高效的Reactor线程模型。在这种模型中,线程之间的职责分工明确,通过有效地分配不同的任务给特定的线程,显著提高了并发性能和系统的可扩展性。

2.5.1 Reactor线程模型基本概念

Reactor线程模型基于Reactor设计模式,这个模式中,一个或多个输入同时传递给服务处理器的事件处理程序,然后服务处理器以同步的方式将这些请求分发到对应的处理器。

2.5.1.1 单Reactor单线程模型

在单Reactor单线程模型中,所有的IO操作(连接/读/写)都在同一个线程中处理,这使得模型非常简单,但是它只能有效处理有限并发量的连接,适合负载较低的场景。

public class SingleReactorSingleThread {// 示意代码,具体实现需要更多的错误处理和资源管理逻辑public static void main(String[] args) throws IOException {Selector selector = Selector.open();ServerSocketChannel serverChannel = ServerSocketChannel.open();serverChannel.configureBlocking(false);serverChannel.socket().bind(new InetSocketAddress(PORT));serverChannel.register(selector, SelectionKey.OP_ACCEPT);// Event Loopwhile (!Thread.interrupted()) {selector.select();Set<SelectionKey> keys = selector.selectedKeys();for (SelectionKey key : keys) {// 处理IO事件if (key.isAcceptable()) {// 接受连接} else if (key.isReadable()) {// 读操作} // ...}keys.clear();}}
}
2.5.1.2 单Reactor多线程模型

单Reactor多线程模型中,一个线程处理所有IO的接入事件,其他线程处理IO的读写。这个模型与单线程模型不同之处在于,它通过线程池处理多个客户端的并发连接。

2.5.1.3 主从Reactor多线程模型

在主从Reactor多线程模型中,有一个主Reactor负责监听所有的连接事件并将这些事件分配给从Reactor,从Reactor再将这些连接分配给工作线程去处理(例如读写事件)。这种分层的方式可以有效地利用CPU资源,提高处理能力,特别适用于连接数较多的高并发场景。

2.5.2 Netty中的Reactor模式应用

Netty的EventLoopGroup就是一种主从Reactor模式的体现,其中bossGroup负责处理连接事件,workerGroup负责处理客户端的socket读写。Netty默认为每个EventLoopGroup提供了N个EventLoop,其中N默认是CPU核数的两倍,每个EventLoop都有自己的Selector。

EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {@Overridepublic void initChannel(SocketChannel ch) throws Exception {ch.pipeline().addLast(/* 注册你的handler */);}}).option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, true);
// 绑定端口并启动服务
b.bind(portNumber).sync().channel().closeFuture().sync();

这段代码显示了Netty如何配置主从Reactor多线程模型。bossGroup 是负责接收进来的连接,而 workerGroup 则是负责处理已经被接收的连接。一旦 bossGroup 接受了连接并注册到 workerGroup,它会交由其中一个 EventLoop 来处理,进而处理所有该连接上的 IO 操作。
这种模型非常适合处理高并发网络请求,因为它可以高效地管理多线程并发,同时避免了一个连接阻塞其他连接的情况。Netty通过优化Reactor模型来确保即便是成千上万的并发连接也不会拖垮服务。

2.6 无锁设计、线程绑定

Netty通过无锁设计和智能线程绑定进一步提高了性能。无锁设计减少了争用条件,而线程绑定则确保了数据局部性和高效的任务处理。

2.6.1 无锁化机制及其重要性

在高并发场景下,锁会成为性能瓶颈,因为它会导致线程阻塞和上下文切换。无锁化设计依赖于CAS(Compare-and-Swap)等原子操作来管理共享资源,避免了显式锁的使用,从而降低了线程阻塞的可能性。

2.6.2 Netty中的无锁化策略

Netty在许多关键组件中使用无锁化策略。例如,Channel 和 EventLoop 之间的关系是一对一的,这样就避免了同一个 Channel 被多个线程同时操作的情况。此外,Netty的异步模型大部分基于被称为Promise的Future实现,此设计允许通过回调进行结果处理,而无需等待或锁定线程。

2.6.3 线程绑定技术实现与优势

线程绑定可确保让处理任务的线程始终固定,这样可以减少线程调度时的开销和提高缓存的利用率。Netty在内部大量使用了EventLoop,它是一个不断循环的执行器,在它的生命周期内,它始终绑定了特定的线程来处理所有的IO事件和任务。
通过这样的设计,Netty充分利用了现代CPU的多核特性,避免了不必要的线程上下文切换,并提高了线程的缓存命中率,极大地提高了性能。

2.7 高性能的序列化框架

高效的数据序列化对于任何需要网络传输数据的应用程序都至关重要,特别是在使用Netty这样的高性能网络框架时。序列化过程需要尽可能少的资源消耗,同时在网络上传输的数据量也需要足够小。

2.7.1 高效序列化框架概述

Netty支持多种序列化协议,其中包括自定义的编解码器等。选择或者实现一个高效的序列化框架,意味着要在保留数据结构丰富性的同时,最大程度地减少序列化数据的大小以及序列化与反序列化的时间。

2.7.2 小包封大包策略,防止网络阻塞

Netty提供了一种叫做“粘包/拆包”的处理机制,对于网络编程特别是TCP传输来说,数据粘包和拆分是常见的问题。Netty通过提供ByteToMessageDecoder和LengthFieldBasedFrameDecoder等解码器支持选择适当的策略来处理这些问题。小包封大包是其中的一种技术,它可以减少网络交互的次数,从而避免网络阻塞,改善了性能。

2.7.3 软中断Hash值和CPU绑定优化

在Netty中,线程和CPU核的亲和性也是一个提升性能的关键因素。通过软中断与Hash值技术可以将网络连接固定到某个CPU核心,减少核间的切换,提升处理效率。
软中断是指利用操作系统特性,避免线程的真实中断,减少中断处理的开销。并且通过计算Hash值来决定处理事件的线程,可以有效地将负载分散到不同的CPU核心上。

public class HashingStrategy {public static int calculateHash(SocketChannel channel) {// 这里的实现可以非常灵活,一种简单的策略是使用远端IP和端口的组合的hashCodeInetSocketAddress remoteAddress = (InetSocketAddress) channel.remoteAddress();String remoteString = remoteAddress.getAddress().getHostAddress() + ":" + remoteAddress.getPort();return remoteString.hashCode();}
}

在Netty的EventLoop实现中,可以利用上述HashCode来确定特定通道在哪个EventLoop中进行处理,从而达到优化CPU使用的目的。

3.实战演练:打造高性能的Netty应用

在本章,我们将通过一系列实战演练,学习如何构建一个高效的Netty服务器和客户端,并进行性能调优。

3.1 构建高效的Netty服务器

构建一个高效的Netty服务器不仅需要理解Netty的高性能特质,同样也需要在实际使用中做出恰当的设计决策和调优。

3.1.1 选择适合的线程模型

线程模型对Netty应用性能有着决定性的影响。Netty提供了多种线程模型配置,最常见的包括单线程模型、多线程模型,以及主从多线程模型。一般情况下,对于小型或中等负载的应用,单Reactor单线程模型就足够有效;而在高负载场景下,主从Reactor多线程模型可以提供更好的性能表现。

// 主从Reactor多线程模型的配置示例
EventLoopGroup bossGroup = new NioEventLoopGroup(1); // 接受新连接
EventLoopGroup workerGroup = new NioEventLoopGroup(); // 处理已经接受的连接
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new YourServerInitializer()) // 设置你的ChannelInitializer// ... 省略其他配置项

3.1.2 优化内存和缓冲策略

内存和缓冲策略对服务器的性能也非常关键。首先要确保合理使用Direct Buffer来减少内存拷贝操作。其次,在可能的情况下重用Buffers,可以通过Netty提供的ByteBufAllocator来实现,它会减少内存的分配和回收频率,从而增加性能。

// 使用Pooled ByteBufAllocator示例
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);

3.2 构建高性能的Netty客户端

客户端实现也是高性能Netty应用的重要组成部分,合理的设计和优化同样能实现高效的数据传输。

3.2.1 客户端连接管理

良好的连接管理策略是客户端性能优化的关键。Netty客户端应当重用连接以减少频繁建立和关闭连接的开销。可以使用ChannelPool来管理和复用连接。

// ChannelPool的简单使用示例
ChannelPool channelPool = new FixedChannelPool(bootstrap, new YourChannelPoolHandler(), 50); // 假设池化大小为50

3.2.2 通过Netty实现高效通信

Netty客户端要实现高效通信,除了需要使用异步请求以降低阻塞,合理地编排业务逻辑和网络调用也很关键。可以结合使用Future和Listener来进行非阻塞的数据处理和发送。

// 异步请求与回调处理示例
Channel channel = ... // 获取一个通道实例
ByteBuf someMessage = ... // 创建要发送的消息
ChannelFuture future = channel.writeAndFlush(someMessage); // 异步发送消息
future.addListener(new ChannelFutureListener() {@Overridepublic void operationComplete(ChannelFuture future) {if (future.isSuccess()) {// 操作成功,处理成功的情况} else {// 操作失败,处理异常情况Thrrowable cause = future.cause();// 日志记录或异常处理逻辑}}
});

这段代码演示了通过Netty客户端异步发送消息以及添加Listener以监听操作完成的过程。这种方式确保了即使在等待IO操作完成时,执行线程也能继续执行其他任务,从而提高整个应用程序的效率。

3.3 性能调优案例

在实际项目中,合理的性能调优可以让Netty应用运行得更加流畅,这通常需要针对具体的业务场景进行测试和调整。

3.3.1 案例分析:实现高吞吐量Netty服务

设想我们需要为一个高并发的数据分析服务构建后端。这个服务需要处理成千上万的并发请求,并且尽可能快地返回数据。对此,我们可以利用Netty的高性能网络处理能力来实现服务。不仅要利用异步IO模型,还应当采用高效的线程策略,比如使用主从Reactor多线程模型。

3.3.2 调优策略和实践技巧

针对实现高吞吐量的Netty服务,调优可能包括:

  • 优化内存使用: 适当的内存策略可以减小全面性能成本,比如使用内存池和合理的GC策略。
  • 调整TCP参数: 例如,适当的TCP缓冲区大小、Backlog大小,甚至是TCP_NO_DELAY和SO_KEEPALIVE等选项都可以调优。
  • IO线程和业务线程分离: 避免在IO线程执行复杂的业务计算,这会导致不必要的延迟。
  • 使用高效的编解码器: 选择合适的协议和编解码框架,减少序列化和反序列化的消耗。

通过这些策略,我们可以进一步提升Netty后端服务的性能,拥抱更多用户的并发访问,同时保持低延迟和高可靠性。

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

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

相关文章

二进制分析 ELF格式

简介: ELF 用于可执行文件&#xff0c;对象文件&#xff0c;共享库及核心转储&#xff0c;是UN IX系统实验室作为二进制接口而开发和发布 组成部分ELF 头部 该头部是一系列结构化的字节&#xff0c;描述是什么样的二进制文件及在文件的什么地方找到其他内容 可以在 /usr/includ…

一文了解经典报童模型的扩展问题

文章目录 1 引言2 经典报童模型3 综述文章4 模型扩展4.1 扩展目标函数4.2 增加约束条件4.3 增加优化变量4.4 扩展模型参数4.5 扩展问题场景 5 总结6 相关阅读 1 引言 时间过的真快呀&#xff0c;已经6月份了。距离上一篇文章发表&#xff0c;已经过去了将近一个月&#xff0c;…

godot.bk:how to add map to the game

1.项目构建如下&#xff0c;map是我们点击start之后才渲染出来的 mian.tscn --main.gd --background(textureact) --start(button) --button.gd sourceFile map.tscn --tilemap --tileset 2.main.gd&#xff1a;注意main.gd并不定义信号&#xff0c;它只是接收信号而已 extend…

Python冷知识

Python作为一种广泛使用的编程语言,有许多功能和特性可能不为初学者或普通用户所熟知。以下是一些相对冷门但有趣的Python知识: 魔术方法:Python中有一些特殊的方法,通常以双下划线__开头和结尾,被称为魔术方法(或特殊方法)。例如,__init__用于初始化对象,__str__返回…

冒泡排序与快速排序

博主主页: 码农派大星. 数据结构专栏:Java数据结构 数据库专栏:MySQL数据库 关注博主带你了解更多数据结构知识 1.冒泡排序 冒泡排序 private static void swap(int[] arrary,int i,int j){int tmp arrary[i];arrary[i] arrary[j];arrary[j] tmp;public static void bubbl…

Java筑基-面向对象

Java-面向对象 一、类和对象1、类和对象的关系2、创建类3、创建对象4、成员变量与局部变量5、构造器5.1、创建对象的过程5.2、构造器的格式5.3、构造器和方法的区别5.4、构造器的作用5.5、构造器的重载 6、this关键字用法&#xff1a;6.1、this可以修饰属性6.2、this可以修饰方…

【Ubuntu常用命令】终端个人常用命令总结

【Ubuntu常用命令】终端常用命令总结 查看硬盘挂载情况查看内存占用情况移动或重命名文件和目录复制文件或目录conda安装本地文件 查看硬盘挂载情况 mount 命令会列出当前系统上所有已挂载的文件系统。它会显示挂载点、文件系统类型、挂载选项等信息 mount df 命令用于显示文…

使用 pm2 或 screen 等工具来管理和后台运行你的 Node.js 应用

使用 pm2 或 screen 等工具来管理和后台运行你的 Node.js 应用。 使用 pm2 pm2 是一个用于 Node.js 应用的进程管理工具&#xff0c;提供了守护进程、日志管理和应用重启等功能。 安装 pm2&#xff1a; npm install pm2 -g启动你的 Node.js 应用&#xff1a; pm2 start se…

outlook邮箱使用技巧

Microsoft Outlook 是一款广泛使用的电子邮件客户端&#xff0c;它提供了许多功能来帮助用户有效地管理电子邮件、日程、联系人等。下面是一些实用的Outlook邮箱使用技巧&#xff0c;可以帮助你提高工作效率和邮件管理效能&#xff1a; ### 1. 快速搜索 - **使用搜索功能**&am…

【一小时学会Charles抓包详细教程】Charles 抓包相关设置 (7)

&#x1f680; 个人主页 极客小俊 ✍&#x1f3fb; 作者简介&#xff1a;程序猿、设计师、技术分享 &#x1f40b; 希望大家多多支持, 我们一起学习和进步&#xff01; &#x1f3c5; 欢迎评论 ❤️点赞&#x1f4ac;评论 &#x1f4c2;收藏 &#x1f4c2;加关注 Charles 抓包相…

数据库(18)——DCL权限控制

MySQL常用权限 权限说明ALL,ALL PRIVILEGES所有权限SELECT查询数据INSERT插入数据UPDATE修改数据DELETE删除数据ALTER修改表DROP删除数据库/表/视图CREATE创建数据库/表 DCL语法 查询权限 SHOW GRANTS FOR 用户名主机名; 查询hello的权限 SHOW GRANTS FOR hellolocalhost; 授…

02.了解容器的发展史

容器技术的发展过程 1&#xff09;:chroot技术&#xff0c;新建一个子系统&#xff08;拥有自己完整的系统文件&#xff09; 参考资料&#xff1a;https://www.ibm.com/developerworks/cn/linux/l-cn-chroot/ chang root 使用chroot监狱限制SSH用户访问指定目录和使用指定命…

【ARIMA时序预测】基于支持向量机结合ARIMA-SVM实现风电功率预测附matlab代码

% 步骤1&#xff1a;加载风电功率数据 load(‘wind_power_data.mat’); % 假设数据存储在变量power_data中 % 步骤2&#xff1a;划分训练集和测试集 trainRatio 0.7; % 训练集比例 trainSize floor(trainRatio * length(power_data)); trainData power_data(1:trainSize); …

GCB | 基于36年5个生态系统观测数据发现表层土壤深度提高生态系统的生产力和稳定性

陆地生态系统生产力对全球粮食安全和促进碳固存至关重要&#xff0c;但生产力受到气候变化以及火灾、干旱、洪水、霜冻频率增加和生物多样性减少的压力。了解控制生态系统初级生产力变异的不同因素和机制&#xff0c;为维持生态系统初级生产力和增强生态系统恢复力提供了科学依…

LeetCode题练习与总结:不同的子序列--115

一、题目描述 给你两个字符串 s 和 t &#xff0c;统计并返回在 s 的 子序列 中 t 出现的个数&#xff0c;结果需要对 10^9 7 取模。 示例 1&#xff1a; 输入&#xff1a;s "rabbbit", t "rabbit" 输出&#xff1a;3 解释&#xff1a; 如下所示, 有 …

OJ1230进制的转换

答案&#xff1a; #include <bits/stdc.h> using namespace std; using lllong long; const int N10; int a[10]; char ch[]{0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F}; void solve() {int n,m;cin>>n>>m;string str;cin>>str;for(int i0;i<str.size();i)…

字符串操作java

题目&#xff1a; 描述 给定长度为n的只有小写字母的字符串s&#xff0c;进行m次操作&#xff0c;每次将[l,r]范围内所有c1字符改成c2&#xff0c;输出操作完的字符串 输入描述&#xff1a; 第一行两个数n,m 第二行一个字符串s 之后m行&#xff0c;每行两个数l 、r两个字符…

Android 系统APP提高CPU优先级,抢占不到CPU

系统APP提高CPU优先级,抢占不到CPU 1.在Android系统中,每个进程都有一个优先级,系统会根据进程的优先级来分配CPU资源。有时候android设备开机的时候负载过高,优先级较低抢占不到cpu,我们需要提高某个进程的优先级,以确保该进程能够顺利执行。 2.开发一个后台任务,需要在…

debian 将pdf 转换为jpg图片

打开终端并执行以下命令来安装这些工具&#xff1a; sudo apt-get update sudo apt-get install imagemagick ghostscript安装完成后&#xff0c;您可以使用convert命令转换PDF到JPEG&#xff1a; convert -density 300 input.pdf[0] output.jpg这里的-density 300参数是设置…

【STL】优先级队列用法介绍及其实现

目录 前言 用法介绍 模拟实现 仿函数 迭代器区间构造 插入 删除 队顶 判空 大小 完整代码 前言 优先级队列&#xff08;priority_queue&#xff09;是一种特殊的队列数据结构&#xff0c;其中每个元素都有一个“优先级”。优先级最高的元素最先出队&#xff0c;而优…