十.吊打面试官系列-Tomcat优化-通过压测Tomcat调优实战
前言
上一篇文章我们讲解了一下Tomcat底层的结构和执行原理,我们需要重点去掌握的是Tomcat的高内聚低耦合的设计,以及责任链模式,以及Tomcat NIO编程模式,这些是Tomcat比较核心的点,本篇文章我们将对Tomcat的参数做一些了解,然后通过Jemeter压测来对Tomcat进行调优。
一.Tomcat参数
首先我们来了解一下Tomcat可以优化的参数,官方文档上有详细的解释 :https://tomcat.apache.org/tomcat-8.0-doc/config/index.html

1.Connector 连接器优化
Connector连接器是用来处理客户端请求的,Tomcat主要提供了 BIO,NIO,AIO 三种方式,BIO是同步阻塞,适用于少量请求的情况,NIO是同步非阻塞,适用于连接数多并发高的业务场景。Tomcat8默认使用NIO,一般也不需要去修改,如果需要修改IO模式修改server.xml 的Connector
<Connector port="8080" protocol="HTTP/1.1"connectionTimeout="20000"redirectPort="8443"maxParameterCount="1000"/>
protocol=“HTTP/1.1” 默认NIO , 直接修改
- protocol=“org.apache.coyote.http11.Http11NioProtocol” : NIO
- protocol=“org.apache.coyote.http11.Http11Protocol” : BIO ,Tomcat9已经移除
- protocol=“org.apache.coyote.http11.Http11AprProtocol” :AIO ,不稳定,性能没有想象中那么高,不用
所以:连接器一般不用优化
2.Executor 线程池优化
配置文档:https://tomcat.apache.org/tomcat-8.0-doc/config/executor.html
Tomcat底层通过Excutor线程池来处理任务,线程池是我们可以优化的点,如果对线程池不理解的同学可以先去恶补一下哦。官方文档中提供了几个重要的参数
maxThreads (int)
该池中活动线程的最大数量,默认为200 ,最大线程数是一个很重要的优化点,我们应该根据机器的性能去合理设置。优化方案:通常情况下通过压测工具去压测Tomcat,然后修改最大线程数,当CPU及内存占用在80%左右,且平均响应时间和吞吐量达到最优,那么这就是一个合理的线程数。
要注意的是线程数不是越大越好,线程数过多,CPU在线程中的上下文切换会越耗时,反而会导致整体性能下降,或者CPU 100%导致系统卡死的情况。但是如果线程数过少会导致无法充分发挥CPU性能,所以通过压测来修改最大线程数是比较合理的方式。网上也有一些通用公式:线程数 = CPU核心数 * (1 + IO耗时/CPU耗时) ,这个也只能作为参考不一定适合所有场景。
minSpareThreads(int)
始终保持活动状态的最小线程数(空闲和活动),默认为25 , 最小线程数可以根据预估并发量来调整,当并发上来minSpareThreads 线程消耗完就会创建新的线程,最大可以创建maxThreads个线程。
maxIdleTime (int)
非核心线程最大空闲时间,超过这个时间线程会被销毁,默认1分钟,该值一般不需要怎么调整。
maxQueueSize (int)
线程池的等待队列,当最大线程数都使用完之后,请求会在队列中排队,默认值为Integer.MAX_VALUE ,当所有的线程都在忙碌,而队列也满了的时候,请求就会被拒绝,该值根据并发量 和 平均响应时间 预估进行设置,
如果不设置很有可能一瞬间来了大量的请求都会被Tomcat接受从而把资源(CPU/内存)消耗空导致服务器宕机。
我们应该对服务器有一个基本的负载能力预估,比如:我只能处理每秒500的请求,那么注定超过500的请求是需要拒绝掉的,我们需要在响应时间和资源利用率之间找到一个平衡点,所以:如果,队列设置太大会导致大量请求等待,造成平均耗时较长。设置太小又回导致大量请求被拒绝,你需要通过监控和性能测试来确定最佳的maxQueueSize值。观察系统的响应时间、吞吐量、资源利用率等指标,并根据这些指标来调整队列大小。这里给点建议:如果是计算型业务,可以设置几十到几百,如果是IO型业务,可以设置到几百到一千。配置如下:
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-" maxQueueSize="200"maxThreads="200" minSpareThreads="24"/><Connector executor="tomcatThreadPool"port="8080" protocol="HTTP/1.1"connectionTimeout="20000"redirectPort="8443"maxParameterCount="1000" />
3.关闭不要功能
Tomcat有一些组件在某些业务场景下是不需要的,开启后会消耗服务器资源,可以选择关闭
删除AJP
AJP是Tomcat用来兼容阿帕奇的,一般我们都用不到,所以可以在server.xml配置文件中把他删除或者注释
<Connector protocol="AJP/1.3"address="::1"port="8009"redirectPort="8443"maxParameterCount="1000"/>
关闭热部署
Tomcat的autoDeploy表示自动部署,即热部署。当autoDeploy设置为true时,Tomcat会检查appBase目录下是否有新的或被覆盖的WAR包,并会重新加载web程序。这样,你就可以在不重启Tomcat的前提下部署程序,也是比较消耗性能的,生产环境中可以关闭 : autoDeploy=“false”
<Host name="localhost" appBase="webapps"unpackWARs="true" autoDeploy="false">
另外一个就是 reloadable属性,用于控制Tomcat在运行时是否监视Web应用程序的/WEB-INF/classes和/WEB-INF/lib目录下class文件的改动,关闭如下:
<Context docBase="your_webapp_path" path="/your_webapp" reloadable="false"> ...
</Context>
关闭默认Servlet
Tomcat提供了处理html静态资源的DefaultServlet,和处理JSP的JSPServlet,在齐纳后端分离的项目中一般是不需要Tomcat去处理今天资源。而是通过Nginx做动静分离了,所以是可以把它关闭,找到web.xml把下面配置注释即可
<servlet><servlet-name>default</servlet-name><servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class><init-param><param-name>debug</param-name><param-value>0</param-value></init-param><init-param><param-name>listings</param-name><param-value>false</param-value></init-param><load-on-startup>1</load-on-startup></servlet><servlet><servlet-name>jsp</servlet-name><servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class><init-param><param-name>fork</param-name><param-value>false</param-value></init-param><init-param><param-name>xpoweredBy</param-name><param-value>false</param-value></init-param><load-on-startup>3</load-on-startup></servlet>
其实还可以关闭的东西有很多,比如Websocket,session 如果你用不到都可以把他关闭,这样就可以把资源节约出来了。
4.启用数据压缩
Tomcat可以通过配置其服务器设置来启用压缩功能,以减少网络传输的数据量并提高网站的性能和加载速度。
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" compression="on" compressionMinSize="2048" compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain" />
- compression : 开启压缩
- compressionMinSize : 小于2M不压缩
- compressableMimeType :针对于哪些数据进行压缩
二.Tomcat项目压测
1.准备项目
IDEA导入Tomcat源码后,创建一个Servlet,在Service方法中sleep 100毫秒模拟方法的耗时,代码如下
public class MyDefaultServlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {try {Thread.sleep(100);System.out.println("================成功访问到Service================");} catch (InterruptedException e) {throw new RuntimeException(e);}}
}
然后找到web.xml文件对Servet做配置,把url映射到 createOrder 路径
<servlet><servlet-name>MyDefaultServlet</servlet-name><servlet-class>org.apache.catalina.servlets.MyDefaultServlet</servlet-class></servlet><servlet-mapping><servlet-name>MyDefaultServlet</servlet-name><url-pattern>/createOrder</url-pattern></servlet-mapping>
项目启动后,我们就可以通过 http://localhost:8080/createOrder来访问项目了
2.JConsole指标监控
Tomcat优化不是盲目设置参数,在Tomcat调优的过程中我们需要对相关参数指标进行监控,比如:错误数、线程池、CPU 以及 JVM 内存等等,根据真实的执行情况进行调试。这里我们通过Java自带的监控工具 jconsole 来监控Tomcat 。 使用cmd执行 jconsole ,然后在本地连接里面找到Tomat的启动进程,点击连接

如果是远程的话需要开启远程连接,我们可以在 Tomcat 的 bin 目录下新建一个名为setenv.sh的文件,内容如下
1 export JAVA_OPTS="${JAVA_OPTS} -Dcom.sun.management.jmxremote"
2 export JAVA_OPTS="${JAVA_OPTS} -Dcom.sun.management.jmxremote.port=8011"
3 export JAVA_OPTS="${JAVA_OPTS} -Djava.rmi.server.hostname=x.x.x.x"
4 export JAVA_OPTS="${JAVA_OPTS} -Dcom.sun.management.jmxremote.ssl=false"
5 export JAVA_OPTS="${JAVA_OPTS} -Dcom.sun.management.jmxremote.authenticate=false"
这样 JMX 的监听端口 8011 就开启了,接下来通过 JConsole 来连接这个端口。

在概览中可以看到:堆内存,线程数,CPU占用率等几个重要指标,下面是线程情况,我们可以看到工作线程,Poller线程,Acceptor线程情况。

有了这些指标我们就可以结合压测工具进行压测,一般在极限压力下CPU和内存使用率达到80%较佳,然后不停的调整Tomcat相关参数,比如:线程池数量,JVM内存大小等,以至于达到一个追加的吞吐量。
我们还可以再MBean里面看到一些核心类的值,比如:请求数量,错误数量等等

3.jemeter工具安装
下载jemeter压测工具:https://jmeter.apache.org/download_jmeter.cgi ,下载后解压,找到bin/jemeter.bat 启动。启动后切换一下语言环境 :options - choose language - chinese

然后再测试计划中 - 右键 - 新建线程组,线程组就是用来模拟客户端的请求的

然后设置线程数,和时间,比如:模拟2S钟500个请求,循环发送10次(一共5000个样本),也可以一直循环发送

添加Http请求,线程组 - 右键 - 添加取样器 - Http请求,然后指定好Tomcat的ip:port和资源路径

如果需要设置请求参数可以在 参数一栏设置

然后给线程组添加 结果报告或者 聚合报告来监控压测结果

4.开始压测
点击:开始按钮,jemeter就会按照设定的线程数向后端发请求进行压力测试了,测试的结果在聚合报告中可以查看,压测效果如下

大概含义是:总共发送了5000个请求,平均耗时 207毫秒,最小耗时100毫秒,最大耗时685毫秒,吞吐量: 每秒1307个请求。
我们可以把线程组 - 循环勾上,这样可以一直让jemeter发请求进行压测,然后观察JVM情况如下:

从jconsole中来看,线程峰值是218,堆内存的使用150M都不到,CPU使用率也才1%不到,这是因为我的电脑配置是:12核,24G内存。所以我的资源使用率是很低的,可以尝试把Tomcat线程数调大。
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"maxThreads="1000" minSpareThreads="500"/><Connector port="8080" protocol="HTTP/1.1"executor="tomcatThreadPool"connectionTimeout="20000"redirectPort="8443"maxParameterCount="1000"/>
然后把jemeter的压测数据调大,改成1000线程,1s ,然后循环压测效果如下:

这一次堆内存占用达到了:600M ,线程峰值达到了 1020个线程,cpu使用率:2%左右(CPU太强悍了) ,jemeter压测效果:达到了 8600+ QPS ,如下

QPS变高了,但是也出现了错误率,错误率一般是因为并发太高,一瞬间请求太多(1000/1s)导致Tomcat处理不过来拒绝了请求导致的。我们继续加大压测力度,jemeter线程数调整为 2000 ,然后再加大 Tomcat线程数到 2000
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"maxThreads="2000" minSpareThreads="1000"/>
持续一分钟,jemeter 压测效果如下: 尽管我们把线程数调到 2000,压测出来的吞吐量反而降到了6000左右,而且最大耗时接近9S了,所以Tomcat线程数并不是越大越好

尽管Tomcat官方说的NIO最大可以处理到(1024 * 8)个连接,但是它并不适合你的机器,我们接下里就是不停的去压测和调整线程数获取其他参数来使性能达到最优即可。当然我这里的测试并不精准,因为我使用的是本地PC测试。 项目本身,Jemeter压测工具,Jconsole监控工具都在 本地,都在抢夺CPU和内存,同时还需要考虑 网络开销,所以只能做一个相对值的参考。
在企业中我们应该把应用部署在真实的服务器上,然后在本地通过jemeter远程压测才能测试出真实的效果,然后一边压测一边调试相关参数。
三.其他方面调优
一个系统的性能遵循漏桶原则,所以系统调优需要从多方面进行,比如:应用本身的性能优化的再好,但是业务很耗时,一样会拖慢整体性能。业务很快但是网络不行,也会导致整体性能降低,下面我们从几个方面,讨论一下优化思路。
上面案例中我睡眠了100毫秒来模拟业务耗时,假如我业务耗时只有10毫秒会发生什么情况,是不是性能直接提升十倍呢? 所以我们的业务耗时越小,应用的整体QPS也会越高,在实际的开发中我们优化业务的思路有很多,比如:
1.算法优化
业务越快越好:假如 1个线程1s能处理1次业务,那么200个线程1s能处理200个业务,如果把业务耗时减少到10毫秒,那么整体的性能提升 100倍: 200 * (1000 / 10) = 20000 ,这是理论数据,所以业务越快越好。
优化算法,让代码变得高效,比如:减少嵌套循环,避免大数据循环嵌套处理
2.数据库优化
业务处理难免会和数据库打交道,数据库的数据基于磁盘IO,Java应用和数据库交互也会产生网络IO,当表数据较大时SQL处理就会比较慢,会拖慢整个业务,所以需要做数据库优化,比如:SQL优化,索引优化,主从优化,大表拆解等从而提升查询速度
3.缓存优化
使用缓存:减少数据库操作,减少数据库交互次数,或直接基于Redis 或 本地内存操作。甚至使用Nginx缓存 ,CDN缓存,客户端缓存等
4.优化JVM
高并发下会瞬间创建大量的对象,当内存不够时频繁触发GC,GC的时候会出现STW(停顿应用线程来执行垃圾回收)导致业务处理耗时边长。这个时候就需要进行JVM优化,通过设置JVM参数来减少CG,或者减少Full GC ,选择合适的垃圾回收器也能很大程度提升应用性能。
ps:避免在for循环中new对象哦!!!
5.异步优化
业务能够使用异步就尽可能异步话,可以通过线程池来加大业务处理速度。或者通过MQ消峰,把耗时的部分业务异步处理,能大大提升业务处理速度。
6.硬件优化
给机器或应用增加 内存和CPU,或者网络带宽对性能的提升是非常大的,比如:同样的条件下,2核CPU核8核CPU带来的性能体验是完全不一样的。
7.集群优化
单机优化不动了就可以通过加机器做集群,通过Lvs集群+nginx集群(单机3-5W并发)实现负载均衡,把请求负载到多台Tomcat上一起来处理业务,加入:一台机器能处理2000QPS,那么搞10台就可以处理2W QPS。也可以使用F5这种负载均衡器,他的并发能力可以达到几十万+,可不是Nginx能比的
8.机房分流
如果用户量非常大遍布全国各地,那么可以做CDN分流,比如:成都机房部署一套集群架构能够承担 20W并发,那么根据用户群分布,我可以在上海,北京,杭州等多地都部署几套,然后通过CDN把用户流量负载均衡到对应城市的机房集群中,这样一来每秒百万级请求都可以处理。
所以:说到最后想要抗住高并发,就是加机器,加钱。然而并发量能够每秒上万的项目又有多少,不占20%把。
看到最后的兄弟评论区见:评论区打 “我看到最后啦”
相关文章:
十.吊打面试官系列-Tomcat优化-通过压测Tomcat调优实战
前言 上一篇文章我们讲解了一下Tomcat底层的结构和执行原理,我们需要重点去掌握的是Tomcat的高内聚低耦合的设计,以及责任链模式,以及Tomcat NIO编程模式,这些是Tomcat比较核心的点,本篇文章我们将对Tomcat的参数做一…...
JVM调优—减少FullGC
背景 最近负责了一个审批流程新项目,带领了几个小伙伴,哼哧哼哧的干了3个月左右,终于在三月底完美上线了,好消息是线上客户用的很丝滑,除了几个非常规的业务提单之外,几乎没有什么大的问题,但是…...
力扣 256. 粉刷房子 LCR 091. 粉刷房子 python AC
动态规划 class Solution:def minCost(self, costs):row, col len(costs), 3dp [[0] * col for _ in range(row 1)]for i in range(1, row 1):for j in range(col):dp[i][j] costs[i - 1][j - 1]if j 0:dp[i][j] min(dp[i - 1][1], dp[i - 1][2])elif j 1:dp[i][j] m…...
C++STL细节,底层实现,面试题04
文章目录 19. STL19.1. 序列容器19.1.1. vector19.1.1.1. 底层实现和特点19.1.1.2. 常用函数19.1.1.3. emplace_back() vs push_back() 19.1.2. array19.1.2.1. 底层实现和特点19.1.2.2. 常用函数 19.1.3. deque19.1.3.1. 底层实现和特点19.1.3.2. 常用函数 19.1.4 list19.1.4.…...
Linux查看Oracle数据库的环境变量
Linux查看Oracle数据库的环境变量 在Linux上查看Oracle数据库的环境变量,通常涉及检查当前shell会话中已设置的环境变量。这些环境变量可能包括ORACLE_HOME、ORACLE_SID、PATH(可能包含Oracle二进制文件的路径)等。 以下是几种方法来查看这…...
pg数据库学习知识要点分析-1
知识要点1 对象标识OID 在PostgreSQL内部,所有的数据库对象都通过相应的对象标识符(object identifier,oid)进行管理,这些标识符是无符号的4字节整型。数据库对象与相应oid 之间的关系存储在对应的系统目录中…...
【Web】CTFSHOW 七夕杯 题解
目录 web签到 easy_calc easy_cmd web签到 CTF中字符长度限制下的命令执行 rce(7字符5字符4字符)汇总_ctf中字符长度限制下的命令执行 5个字符-CSDN博客7长度限制直接梭了 也可以打临时文件RCE import requestsurl "http://4ae13f1e-8e42-4afa-a6a6-1076acd08211.c…...
react native 设置屏幕锁定
原生配置 android 在android/app/src/main/AndroidManifest.xml在这个文件里的入口activity里添加 android:screenOrientation"portrait" <activityandroid:name".MainActivity"android:label"string/app_name" …...
探索 IPv6 协议:互联网的新一代寻址
目录 一.概述 IPv4 的问题和 IPv6 的新特性 IPv6 协议体系 二.IPv6 寻址架构:巨大的地址空间与灵活的寻址模式 IPv6 寻址概述 地址表示方法 地址前缀与地址类型标识 单播地址 任播地址 多播地址 特殊的 IPv6 地址 IPv6 主机与路由器寻址 地址分配 三.I…...
Ubuntu意外断电vmdk损坏--打不开磁盘“***.vmdk”或它所依赖的某个快照磁盘。
背景:电脑资源管理器崩溃卡死,强行断电重启,结果虚拟机打不开了,提示打不开磁盘“***.vmdk”或它所依赖的某个快照磁盘。 删除lck文件:失败vmware-vdiskmanager修复 :提示无法修复最终用 VMFS Recovery挂载…...
202466读书笔记|《一天一首古诗词》——借问梅花何处落,风吹一夜满关山
202466读书笔记|《一天一首古诗词》——借问梅花何处落,风吹一夜满关山 上册下册 《一天一首古诗词》作者李锡琴,蛮早前加入书架的已购买书籍,这次刚好有点时间,利用起来读完。 赏析没有细看,只读了诗词部分࿰…...
如何调用本地ollama的http请求接口
http://127.0.0.1:11434/api/generate 使用http post请求,参数 { "model": "qwen", "prompt": "为什么天空是蓝色?", "stream": false } 返回结果如下: {"model": "qwen",…...
【C】190 颠倒二进制位
颠倒给定的 32 位无符号整数的二进制位。 提示: 请注意,在某些语言(如 Java)中,没有无符号整数类型。在这种情况下,输入和输出都将被指定为有符号整数类型,并且不应影响您的实现,因…...
蓝桥杯备战5.图书管理员
[NOIP2017]图书管理员 (nowcoder.com) #include<bits/stdc.h> #define endl \n #define int long long using namespace std; const int N 2e510,M1e310; int a[N]; int n,q; int check(int l,int x) {int tmppow(10,l);for(int i1;i<n;i){if(a[i]%tmpx){cout<&…...
微型显示器可以实时监测大脑活动
美国团队开发基于LED的设备,以可视化大脑活动,在脑外科手术中指导神经外科医生 来自加州大学圣地亚哥分校和马萨诸塞州总医院的工程师和医生开发了一种薄膜显示设备,该设备结合了电极网格和特殊的GaN LED,可以在手术过程中实时跟…...
移动端适配方案
移动端适配 方案 1:rem html font-size 方案 2:vw rem html font-size rem 是相对于 html 元素的 font-size 来设置的单位,通过在不同屏幕尺寸下动态修改 html 元素的 font-size 可达到适配效果 在开发中,我们只需要考虑两个…...
【Ajax零基础教程】-----第一课 Ajax简介
一、什么是ajax ajax即 Asynchronous javascript And XML (异步 javaScript 和 XML) 是一种创建交互式,快速动态应用的网页开发技术,无需重新加载整个网页的情况下,能够更新页面局部数据的技术。 二、为什么使用Ajax 通过在后台与服务器进行少…...
大型医疗挂号微服务“马上好医”医疗项目(5)Swagger的使用
Swagger的简单介绍 Swagger 是一个 RESTful 接口文档的规范和工具集,它的目标是统一 RESTful 接口文档的格式和规范。在开发过程中,接口文档是非常重要的一环,它不仅方便开发者查看和理解接口的功能和参数,还能帮助前后端开发协同…...
C语言从头学04——介绍占位符和输出格式
占位符、输出格式都是与 printf() 相关的,当然其它函数也有用到占位符的。这里先介绍它们在 printf() 的使用。 一、先介绍占位符,所谓“占位符”通俗讲就是先占个位置,后边再找具体值(参数)代入进行显示的一种方法。先用一个例子说明…...
写爬虫代码抓取Asterank中小行星数据
2024年5月4日 问题来源 解决方案 回顾2023年7月14日自己写的爬虫代码 import requests import re import pandas as pd texts[] def getData(page):#每页评论的网址urlhttps://item.jd.com/51963318622.html#comment#添加headers,伪装成浏览器headers{User-Agent:…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...
Ascend NPU上适配Step-Audio模型
1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...
Python如何给视频添加音频和字幕
在Python中,给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加,包括必要的代码示例和详细解释。 环境准备 在开始之前,需要安装以下Python库:…...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...
《C++ 模板》
目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板,就像一个模具,里面可以将不同类型的材料做成一个形状,其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式:templa…...
QT3D学习笔记——圆台、圆锥
类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体(对象或容器)QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质(定义颜色、反光等)QFirstPersonC…...
安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲
文章目录 前言第一部分:体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分:体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...
