Netty笔记10-Netty参数调优

news2024/9/20 6:36:31

文章目录

  • 一、CONNECT_TIMEOUT_MILLIS
    • CONNECT_TIMEOUT_MILLIS设置为1秒超时
    • CONNECT_TIMEOUT_MILLIS设置为5秒超时
    • 注意事项
  • 二、SO_BACKLOG
    • 代码示例
    • 注意事项
  • 三、ulimit -n(文件描述符)
    • 设置文件描述符限制
    • 在注意事项
  • 四、TCP_NODELAY
    • 使用 TCP_NODELAY 的场景
    • 注意事项
  • 五、SO_SNDBUF & SO_RCVBUF
    • SO_SNDBUF(发送缓冲区)
      • 作用
    • SO_RCVBUF(接收缓冲区)
      • 作用
  • 六、ALLOCATOR
  • 七、RCVBUF_ALLOCATOR


一、CONNECT_TIMEOUT_MILLIS

在Netty中,CONNECT_TIMEOUT_MILLIS 是一个与连接超时相关的配置选项。这个选项用于设置客户端在尝试建立连接时的最大等待时间。如果在指定的时间内未能成功建立连接,Netty 将会抛出一个 ConnectTimeoutException 异常。

  • 属于 SocketChannal 参数
  • 用在客户端建立连接时,如果在指定毫秒内无法连接,会抛出 timeout 异常
  • SO_TIMEOUT 主要用在阻塞 IO,阻塞 IO 中 accept,read 等都是无限等待的,如果不希望永远阻塞,使用它调整超时时间
  1. 客户端通过 .option() 方法配置参数 给 SocketChannel 配置参数

  2. 服务器端
    new ServerBootstrap().option() ,是给 ServerSocketChannel 配置参数
    new ServerBootstrap().childOption() ,给 SocketChannel 配置参数

CONNECT_TIMEOUT_MILLIS设置为1秒超时

option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1000)

不启动服务器端直接启动客户端观察控制台

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LoggingHandler;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class Test02ConnectionTimeout {
    public static void main(String[] args) {
        NioEventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap = new Bootstrap()
                    .group(group)
                    .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1000)
                    .channel(NioSocketChannel.class)
                    .handler(new LoggingHandler());
            ChannelFuture future = bootstrap.connect("127.0.0.1", 8080);
            ChannelFuture channelFuture = future.sync();//当1秒内没有连接成功,则判断为连接超时所以抛出异常
            channelFuture.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
            log.debug("timeout");
        } finally {
            group.shutdownGracefully();
        }
    }
}

控制台输出

io.netty.channel.ConnectTimeoutException: connection timed out: /127.0.0.1:8080

CONNECT_TIMEOUT_MILLIS设置为5秒超时

option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LoggingHandler;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class Test02ConnectionTimeout {
    public static void main(String[] args) {
        NioEventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap = new Bootstrap()
                    .group(group)
                    .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
                    .channel(NioSocketChannel.class)
                    .handler(new LoggingHandler());
            ChannelFuture future = bootstrap.connect("127.0.0.1", 8080);
            ChannelFuture channelFuture = future.sync();//当1秒内没有连接成功,则判断为连接超时所以抛出异常
            channelFuture.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
            log.debug("timeout");
        } finally {
            group.shutdownGracefully();
        }
    }
}

控制台输出

io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: no further information: /127.0.0.1:8080
Caused by: java.net.ConnectException: Connection refused: no further information

观察发现ChannelOption.CONNECT_TIMEOUT_MILLIS超时时间设置1秒和5秒时报错信息不同,原因是:

  • 设置为5秒是因为在没有启动服务器端时,客户端两秒后判断出服务器端没启动,所以根本连不上。所以直接报错。
  • 设置为1秒是因为还不能判断服务器端是否启动就已经超时了,所以报错连接超时。

注意事项

  • 合理设置超时时间:根据应用场景和网络状况合理设置超时时间。如果网络条件较差,可以适当增加超时时间;如果对响应时间有严格要求,则可以缩短超时时间。
  • 异常处理:在代码中处理 ConnectTimeoutException,可以记录日志,并根据业务需求决定是否重试连接等。
  • 重试机制:可以实现一个重试机制,在首次连接失败后尝试多次连接,直到成功或达到最大重试次数。
  • 监控和报警:设置监控来检测连接超时的发生,并在必要时触发报警,以便及时处理潜在的问题。

二、SO_BACKLOG

在Netty中,SO_BACKLOG 是一个与 TCP 服务器端套接字相关的选项,用于设置在服务器的连接请求队列中可以排队的最大连接数。当客户端尝试连接到服务器时,如果服务器正忙于处理其他连接请求,新的连接请求会被放入这个队列中等待处理。SO_BACKLOG 的值决定了这个队列的最大长度。

Netty中SO_BACKLOG属于 ServerSocketChannal 参数
在这里插入图片描述

  1. 第一次握手,client 发送 SYN 到 server,状态修改为 SYN_SEND,server 收到,状态改变为 SYN_REVD,并将该请求放入 sync queue 队列(半连接队列)
  2. 第二次握手,server 回复 SYN + ACK 给 client,client 收到,状态改变为 ESTABLISHED,并发送 ACK 给 server
  3. 第三次握手,server 收到 ACK,状态改变为 ESTABLISHED,将该请求从 sync queue 放入 accept queue(全连接队列)

其中

  • 在 linux 2.2 之前,backlog 大小包括了两个队列的大小,在 2.2 之后,分别用下面两个参数来控制
  • sync queue - 半连接队列
  • 大小通过 /proc/sys/net/ipv4/tcp_max_syn_backlog 指定,在
    syncookies 启用的情况下,逻辑上没有最大值限制,这个设置便被忽略
  • accept queue - 全连接队列
  • 其大小通过 /proc/sys/net/core/somaxconn 指定,在使用 listen 函数时,内核会根据传入的 backlog 参数与系统参数,取二者的较小值
  • 如果 accpet queue 队列满了,server 将发送一个拒绝连接的错误信息到 client

在netty中可以通过 option(ChannelOption.SO_BACKLOG, 值) 来设置大小

代码示例

public class TestBacklogServer {
    public static void main(String[] args) {
        new ServerBootstrap()
                .group(new NioEventLoopGroup())
                .option(ChannelOption.SO_BACKLOG, 2)
                // 验证全队列满了,客户端在进行连接会报错ConnectException: Connection refused: no further information
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel ch) {
                        ch.pipeline().addLast(new LoggingHandler());
                    }
                }).bind(8080);
    }
}
@Slf4j
public class TestBacklogClient {
    public static void main(String[] args) {
        NioEventLoopGroup worker = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.channel(NioSocketChannel.class);
            bootstrap.group(worker);
            bootstrap.handler(new ChannelInitializer<SocketChannel>() {

                @Override
                protected void initChannel(SocketChannel ch) throws Exception {
                    ch.pipeline().addLast(new LoggingHandler());
                    ch.pipeline().addLast(new ChannelInboundHandlerAdapter(){
                        @Override
                        public void channelActive(ChannelHandlerContext ctx) throws Exception {
                            ctx.writeAndFlush(ctx.alloc().buffer().writeBytes("hello!".getBytes()));
                        }
                    });
                }
            });
            ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 8080).sync();
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            log.error("client error", e);
        } finally {
            worker.shutdownGracefully();
        }
    }
}

第三个客户端连接时报错:

Connected to the target VM, address: '127.0.0.1:43839', transport: 'socket'
19:58:44 [DEBUG] [nioEventLoopGroup-2-1] i.n.h.l.LoggingHandler - [id: 0x95677ae0] REGISTERED
19:58:44 [DEBUG] [nioEventLoopGroup-2-1] i.n.h.l.LoggingHandler - [id: 0x95677ae0] CONNECT: /127.0.0.1:8080
19:58:46 [DEBUG] [nioEventLoopGroup-2-1] i.n.h.l.LoggingHandler - [id: 0x95677ae0] CLOSE
Exception in thread "main" io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: no further information: /127.0.0.1:8080
Caused by: java.net.ConnectException: Connection refused: no further information

注意事项

  1. 操作系统限制:SO_BACKLOG 的实际效果受到操作系统的限制。在 Linux 上,SO_BACKLOG 的值通常会被限制在 somaxconn 系统参数范围内。可以通过查看当前linux系统的 somaxconn 值,并通过 sysctl 命令进行调整。
# 查看 somaxconn 的值
cat /proc/sys/net/core/somaxconn

# 设置 somaxconn 的值
sysctl net.core.somaxconn=1024
  1. 队列满后的处理:如果 SO_BACKLOG 队列满了,新的连接请求将会被拒绝。在这种情况下,客户端会收到一个连接失败的错误。因此,合理设置 SO_BACKLOG 的值很重要,以确保不会因为队列满而导致连接请求被拒绝。
  2. 性能影响:虽然设置较高的 SO_BACKLOG 值可以容纳更多的连接请求,但也可能占用更多的系统资源。因此,需要根据实际的并发需求和系统性能来权衡 SO_BACKLOG 的值。

三、ulimit -n(文件描述符)

文件描述符是操作系统分配给进程用于表示打开的文件、网络连接等资源的整数标识符。在 Linux 和 Unix-like 系统中,每个进程都有一个文件描述符的上限,这个上限由 ulimit -n 命令来查看和设置。
文件描述符是操作系统用来跟踪进程所打开的文件和其他 I/O 资源(如网络连接、管道等)的内部索引。每个打开的文件或 I/O 资源都有一个唯一的文件描述符与之关联。

  • ulimit -n 属于操作系统参数
    作用:显示一个线程同时打开最大文件描述符(FD)的数量,当FD到达上限在打开文件会报错。如果服务器要支持高并发,支持大量的连接就需要调整ulimit参数。

设置文件描述符限制

# 查看当前用户的软限制
ulimit -n

# 设置新的软限制
ulimit -n 65536

# 查看新的软限制
ulimit -n

在注意事项

  • 安全性:增加文件描述符限制可能会增加系统资源的消耗,因此需要根据实际需求和系统能力来设置合适的限制值。
  • 性能:增加文件描述符限制可能会导致系统开销增加,特别是在高并发场景下,因此需要权衡利弊。
  • 系统限制:有些系统对文件描述符的总数有严格的限制,即使你是 root 用户也无法无限制地增加文件描述符的数量。

四、TCP_NODELAY

在Netty中,TCP_NODELAY 是一个与TCP协议相关的选项,用于控制是否禁用Nagle算法。Nagle算法是为了减少小数据包在网络中的传输次数,以减少网络带宽的消耗和网络拥塞。然而,在某些需要低延迟的应用场景中,禁用Nagle算法可以提高实时性能。

  • TCP_NODELAY 属于 SocketChannal 参数
  • 默认false开启了nagle算法(沾包问题数据攒到一起发送),但是一般都需要消息可以及时的发送出去。所以设置为true
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;

public class Client {

    public static void main(String[] args) throws InterruptedException {
        EventLoopGroup group = new NioEventLoopGroup();

        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group)
                     .channel(NioSocketChannel.class)
                     .option(ChannelOption.TCP_NODELAY, true) // 设置 TCP_NODELAY 为 true
                     .handler(new MyClientInitializer());

            // 连接到服务器
            ChannelFuture future = bootstrap.connect("127.0.0.1", 8080).sync();
            if (!future.isSuccess()) {
                System.err.println("Failed to connect: " + future.cause());
            }
        } finally {
            group.shutdownGracefully();
        }
    }
}
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class Server {

    public static void main(String[] args) throws InterruptedException {
        EventLoopGroup bossGroup = new NioEventLoopGroup(1); // 主线程组,用于接受新的连接
        EventLoopGroup workerGroup = new NioEventLoopGroup(); // 工作线程组,用于处理连接上的数据

        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workerGroup)
                     .channel(NioServerSocketChannel.class)
                     .option(ChannelOption.SO_BACKLOG, 128)
                     .childOption(ChannelOption.TCP_NODELAY, true) // 设置 TCP_NODELAY 为 true
                     .childHandler(new ChannelInitializer<NioSocketChannel>() {
                         @Override
                         protected void initChannel(NioSocketChannel ch) {
                             ch.pipeline().addLast(new LoggingHandler());
                         }
                     });

            // 绑定端口并开始监听
            ChannelFuture future = bootstrap.bind(8080).sync();
            future.channel().closeFuture().sync(); // 等待服务器 socket 关闭
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

使用 TCP_NODELAY 的场景

  1. 实时应用
    在实时应用(如在线游戏、实时视频会议等)中,通常需要尽可能低的延迟。在这种情况下,禁用Nagle算法可以提高实时性能,因为数据包会立即发送,而不会被累积。
  2. 高吞吐量应用
    在需要高吞吐量的应用中,累积数据包可以减少网络带宽的消耗。因此,在这类应用中,可以保留Nagle算法的默认设置。

注意事项

性能影响:禁用Nagle算法会增加网络带宽的消耗,尤其是在发送小数据包的情况下。因此,在设置 TCP_NODELAY 之前,需要评估其对性能的影响。
兼容性:确保客户端和服务器端都设置了相同的 TCP_NODELAY 值,以避免由于配置不一致而导致的问题。

五、SO_SNDBUF & SO_RCVBUF

在Netty中,SO_SNDBUF 和 SO_RCVBUF 是两个与套接字缓冲区相关的选项,它们分别用于控制发送缓冲区和接收缓冲区的大小。这两个选项可以帮助优化网络通信性能,特别是在高并发或大数据量传输的场景下。

  • SO_SNDBUF 属于 SocketChannal 参数
  • SO_RCVBUF 既可用于 SocketChannal 参数,也可以用于 ServerSocketChannal 参数(建议设置到 ServerSocketChannal 上)
    这两个参数决定了滑动窗口的上限。一般不建议手动添加,因为操作系统一般会根据通信双方的网络通信能力来调整这两个参数。

SO_SNDBUF(发送缓冲区)

SO_SNDBUF 选项用于设置发送缓冲区的大小。发送缓冲区是操作系统用来暂时存储待发送的数据的一个区域。当应用程序向网络发送数据时,数据首先被写入发送缓冲区,然后由操作系统负责将数据发送到网络上。

作用

提高发送速度:较大的发送缓冲区可以让应用程序更快地将数据写入缓冲区,而不必等待数据实际发送完毕。
减少阻塞:如果发送缓冲区太小,当网络拥塞或接收方处理较慢时,应用程序可能会因为缓冲区满而被阻塞。

SO_RCVBUF(接收缓冲区)

SO_RCVBUF 选项用于设置接收缓冲区的大小。接收缓冲区是操作系统用来暂时存储从网络接收的数据的一个区域。当数据从网络到达时,首先被写入接收缓冲区,然后由应用程序负责从缓冲区中读取数据。

作用

提高接收速度:较大的接收缓冲区可以让操作系统更快地接收数据,而不必等待应用程序处理完毕。
减少丢包:如果接收缓冲区太小,当网络流量较大或应用程序处理较慢时,可能会导致数据包丢失。

六、ALLOCATOR

  • 属于 SocketChannal 参数
  • 用来分配 ByteBuf, ctx.alloc()
    ByteBuf默认使用PooledUnsafeDirectByteBuf
@Slf4j
public class Test04ByteBuf {
    public static void main(String[] args) {
        new ServerBootstrap()
                .group(new NioEventLoopGroup())
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel ch) {
                        ch.pipeline().addLast(new LoggingHandler());
                        ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
                            @Override
                            public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                                ByteBuf buf = ctx.alloc().buffer();
                                log.debug("alloc buf {}", buf);
                                //alloc buf PooledUnsafeDirectByteBuf(ridx: 0, widx: 6, cap: 256)

                                //在设置中VM options配置-Dio.netty.allocator.type=unpooled
                                //alloc buf UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeNoCleanerDirectByteBuf(ridx: 0, widx: 0, cap: 256)

                                //在设置中VM options配置-Dio.netty.allocator.type=unpooled -Dio.netty.noPreferDirect=true
                                //alloc buf UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 0, cap: 256)
                                
//                                log.debug("receive buf {}", msg);
//                                System.out.println("");
                            }
                        });
                    }
                }).bind(8080);
    }
}

在这里插入图片描述

七、RCVBUF_ALLOCATOR

在Netty中,RCVBUF_ALLOCATOR 是一个与接收缓冲区大小相关的配置选项,它用于控制接收缓冲区的初始大小和最大大小。这个配置选项可以帮助优化网络通信性能,特别是在高并发或大数据量传输的场景下。
RCVBUF_ALLOCATOR 用于控制接收缓冲区的分配策略。接收缓冲区是操作系统用来暂时存储从网络接收的数据的一个区域。当数据从网络到达时,首先被写入接收缓冲区,然后由应用程序负责从缓冲区中读取数据。

  • 属于 SocketChannal 参数
  • 控制 netty 接收缓冲区大小
  • 负责入站数据的分配,决定入站缓冲区的大小(并可动态调整),统一采用 direct 直接内存,具体池化还是非池化由 allocator 决定

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

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

相关文章

软件安全最佳实践:首先关注的地方

尽管组织拥有大量可用的工具&#xff0c;但应用程序安全性仍然不足。 最近的数据显示&#xff0c;在过去四到五年中&#xff0c;软件供应链攻击同比增长了 600-700%&#xff0c;超过一半的美国企业在过去 12 个月中遭受过某种形式的软件供应链攻击。 为何应用程序安全工作未…

签署《AI安全国际对话威尼斯共识》 智源持续推动人工智能安全发展

近日&#xff0c;由AI安全国际论坛&#xff08;Safe AI Forum&#xff09;和博古睿研究院&#xff08;Berggruen Institute) 共同举办的第三届国际AI安全对话&#xff08;International Dialogues on AI Safety&#xff09;在威尼斯举办。图灵奖得主Yoshua Bengio、姚期智教授&…

电气设备施工现场风险状态判断ai模型训练数据集

电气设备施工现场风险状态判断ai模型训练数据集 id:18 电气设备施工现场工人人工智能学习数据和工作环境安全数据&#xff0c;建立系统化管理体系&#xff0c;改变全球EHS范式&#xff0c;预防工业事故。数据集记录了387709例子电力设施建设以及施工现场相关的灾害安全环境数据…

VM16安装macOS11

注意&#xff1a; 本文内容于 2024-09-17 12:08:24 创建&#xff0c;可能不会在此平台上进行更新。如果您希望查看最新版本或更多相关内容&#xff0c;请访问原文地址&#xff1a;VM16安装macOS11。感谢您的关注与支持&#xff01; 使用 Vmware Workstation Pro 16 安装 macOS…

数字世界的新秩序:探索Web3的前景

在过去的几十年中&#xff0c;互联网已经彻底改变了我们的生活方式&#xff0c;推动了信息共享、全球互联以及数字经济的快速发展。然而&#xff0c;当前的互联网架构主要是中心化的&#xff0c;由少数大型科技公司控制数据、服务和基础设施。这种模式虽然高效&#xff0c;但也…

Golang | Leetcode Golang题解之第419题棋盘上的战舰

题目&#xff1a; 题解&#xff1a; func countBattleships(board [][]byte) (ans int) {for i, row : range board {for j, ch : range row {if ch X && !(i > 0 && board[i-1][j] X || j > 0 && board[i][j-1] X) {ans}}}return }

微服务注册中⼼2

5.Nacos配置管理 Nacos除了可以做注册中⼼&#xff0c;同样可以做配置管理来使⽤ 5.1 统⼀配置管理 当微服务部署的实例越来越多&#xff0c;达到数⼗、数百时&#xff0c;逐个修改微服务配置就会让⼈抓狂&#xff0c;⽽且很容易出错。我们需要⼀种统⼀配置管理⽅案&#xf…

idea生成类信息及快捷开发配置

目录 一、预言 二、在Java类的开头自动注释作者名字和日期等信息 2.1.各种预设变量 2.2.idea配置 2.3.成品展示 三、快捷开发 3.1.三种循环热键 3.2.if判断 3.3.instanceof运算 3.4.非空判断 3.5.测试打印 3.6. synchronized 3.7.异常抛出 一、预言 在…

Java运算符有哪些?深入解析Java运算符:从基础到进阶的全方位指南(超全表格)

&#x1f4bb;1.前言 在编程中&#xff0c;运算符是处理数据和变量的基本工具。它们不仅使得代码更加简洁&#xff0c;还能极大地提高编程效率。本文还提供了详细的 Java运算符参考表格&#xff0c;涵盖了算术运算符、关系运算符、逻辑运算符、赋值运算符、位运算符、…

Dependency Check:一款针对应用程序依赖组件的安全检测工具

关于Dependency Check Dependency-Check 是一款软件组合分析 &#xff08;SCA&#xff09; 工具&#xff0c;可尝试检测项目依赖项中包含的公开披露的漏洞。它通过确定给定依赖项是否存在通用平台枚举 &#xff08;CPE&#xff09; 标识符来实现此目的。如果找到&#xff0c;它…

Arthas thread(查看当前JVM的线程堆栈信息)

文章目录 二、命令列表2.1 jvm相关命令2.1.2 thread&#xff08;查看当前JVM的线程堆栈信息&#xff09;举例1&#xff1a;展示[数字]线程的运行堆栈&#xff0c;命令&#xff1a;thread 线程ID举例2&#xff1a;找出当前阻塞其他线程的线程 二、命令列表 2.1 jvm相关命令 2.…

展锐平台的手机camera 系统开发过程

展锐公司有自己的isp 图像处理引擎&#xff0c;从2012 年底就开始在智能手机上部署应用。最初的时候就几个人做一款isp的从hal 到kernel 驱动的完整软件系统&#xff0c;分工不是很明确&#xff0c;基本是谁擅长哪些就搞哪些&#xff0c;除了架构和编码实现之外&#xff0c;另外…

Flask项目入门和视图

1、第一个项目的结构 以示例代码中的入口文件app.py为例子 &#xff08;1&#xff09;引入Flask以及创建Flask对象 from flask import Flask app Flask(__name__)&#xff08;2&#xff09; 路由route 视图函数 app.route(/index/) def hello_world():# 响应&#xff1a;…

超详细PS2019安装教程与安装步骤图文解析!保姆级教程!(附赠PS下载地址)

步骤1&#xff1a;下载Adobe Photoshop PS CC 2023下载链接&#xff1a;https://pan.quark.cn/s/f997e116f327 下载完成后&#xff0c;解压文件到当前文件夹&#xff08;随便用什么解压软件都行&#xff0c;现在解压软件都是免费的&#xff0c;没有的到360官网下载360压缩&am…

开源RK3588 AI Module7,并与Jetson Nano生态兼容的低功耗AI模块

RK3588 AI Module7 搭载瑞芯微 RK3588&#xff0c;提供强大的 64 位八核处理器&#xff0c;最高时钟速度为 2.4 GHz&#xff0c;6 TOPS NPU&#xff0c;并支持高达 32 GB 的内存。它与 Nvidia 的 Jetson Nano 接口兼容&#xff0c;具有升级和改进的 PCIe 连接。由于该模块的多功…

Photoshop 2020安装教程

软件介绍 Adobe Photoshop&#xff0c;简称“PS”&#xff0c;是美国Adobe公司旗下最为出名的图像处理软件系列之一。ps 2021新增一键换天空&#xff0c;AI只能滤镜&#xff0c;新增内置的画笔工具极为丰富&#xff0c;成千上万的精致像素、动态和矢量画笔可以满足你的各种绘图…

【Qt | QAction】Qt 的 QAction 类介绍

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…

基于深度学习的手势识别算法(论文复现)

基于深度学习的手势识别算法&#xff08;论文复现&#xff09; 本文所涉及所有资源均在传知代码平台可获取 文章目录 基于深度学习的手势识别算法&#xff08;论文复现&#xff09;概述算法原理核心逻辑效果演示使用方式 概述 本文基于论文 Simple Baselines for Human Pose Es…

在WPF中自定义控件时如何选择基类

在WPF中需要自定义控件&#xff0c;首要要选择需要继承的基类 FrameworkElement 这是常用的最低级的基类。通常&#xff0c;只有当希望重写OnRender()方法并使用DrawingContext从头绘制内容时&#xff0c;才会继承该类。 Control 当从头开始创建控件时&#xff0c;这是最常用…

茴香豆:企业级知识问答工具实践闯关任务

基础任务 在 InternStudio 中利用 Internlm2-7b 搭建标准版茴香豆知识助手&#xff0c;并使用 Gradio 界面完成 2 轮问答&#xff08;问题不可与教程重复&#xff0c;作业截图需包括 gradio 界面问题和茴香豆回答&#xff09;。知识库可根据根据自己工作、学习或感兴趣的内容调…