当前位置: 首页 > news >正文

轻量级动态可监控线程池 - DynamicTp

一、背景介绍 

使用线程池ThreadPoolExecutor的过程中你是否有以下痛点呢?

  • 代码中创建了一个 ThreadPoolExecutor,但是不知道那几个核心参数设置多少比较合适
  • 凭经验设置参数值,上线后发现需要调整,改代码重新发布服务,非常麻烦
  • 线程池相对开发人员来说是个黑盒,运行情况不能及时感知到,直到出现问题

如果有以上痛点,动态可监控线程池框架(DynamicTp)或许可以帮助到我们。 

如果看过 ThreadPoolExecutor 的源码,大概可以知道它对核心参数基本都有提供 set / get 方法以及一些扩展方法,可以在运行时动态修改、获取相应的值,这些方法有:

public void setCorePoolSize(int corePoolSize);
public void setMaximumPoolSize(int maximumPoolSize);
public void setKeepAliveTime(long time, TimeUnit unit);
public void setThreadFactory(ThreadFactory threadFactory);
public void setRejectedExecutionHandler(RejectedExecutionHandler handler);
public void allowCoreThreadTimeOut(boolean value);public int getCorePoolSize();
public int getMaximumPoolSize();
public long getKeepAliveTime(TimeUnit unit);
public BlockingQueue<Runnable> getQueue();
public RejectedExecutionHandler getRejectedExecutionHandler();
public boolean allowsCoreThreadTimeOut();protected void beforeExecute(Thread t, Runnable r);
protected void afterExecute(Runnable r, Throwable t);

现在大多数的互联网项目都会微服务化部署,有一套自己的服务治理体系,微服务组件中的分布式配置中心扮演的就是动态修改配置,实时生效的角色。

那么我们是否可以结合配置中心来做运行时线程池参数的动态调整呢?

答案是肯定的,而且配置中心相对都是高可用的,使用它也不用过于担心配置推送失败这类问题,而且也能减少研发动态线程池组件本身的难度和工作量。 

综上,可以总结出以下的背景:

  • 广泛性在 Java 开发中,想要提高系统性能,线程池已经是一个 90% 以上开发都会选择使用的基础工具
  • 不确定性:项目中可能会创建很多线程池,既有IO密集型的,也有CPU密集型的,但线程池的参数并不好确定,需要有套机制在运行过程中动态去调整参数
  • 无感知性:线程池运行过程中的各项指标一般感知不到;需要有套监控报警机制在事前、事中就能让开发人员感知到线程池的运行状况,及时处理
  • 高可用性:配置变更需要及时推送到客户端,需要有高可用的配置管理推送服务,配置中心是现在大多数互联网系统都会使用的组件,与之结合可以极大提高系统可用性

二、DynamicTp的功能特性

基于以上背景分析,DynamicTp框架对线程池 ThreadPoolExecutor 做一些扩展增强,主要实现以下目标: 

  • 实现对运行中线程池参数的动态修改,实时生效
  • 实时监控线程池的运行状态,触发设置的报警策略时报警,报警信息推送办公平台
  • 定时采集线程池指标数据,配合像 Grafana 这种可视化监控平台做大盘监控

DynamicTp框架的官网地址为:

https://dynamictp.cn/

经过多个版本的迭代,目前最新版本 v1.1.7 具有以下特性:

  • 代码零侵入:我们改变了线程池以往的使用姿势,所有配置均放在配置中心,服务启动时会从配置中心拉取配置生成线程池对象放到 Spring 容器中,使用时直接从 Spring 容器中获取,对业务代码零侵入

  • 通知告警:提供多种报警维度(配置变更通知、活性报警、容量阈值报警、拒绝触发报警、任务执行或等待超时报警),已支持企业微信、钉钉、飞书、邮件报警,同时提供 SPI 接口可自定义扩展实现

  • 运行监控:定时采集线程池指标数据,支持通过 MicroMeter、JsonLog 日志输出、Endpoint 三种方式,可通过 SPI 接口自定义扩展实现

  • 任务增强:提供任务包装功能,实现 TaskWrapper 接口即可,如 MdcTaskWrapper、TtlTaskWrapper、SwTraceTaskWrapper,可以支持线程池上下文信息传递

  • 多配置中心支持:基于主流配置中心实现线程池参数动态调整,实时生效,已支持 Nacos、Apollo、Zookeeper、Consul、Etcd、Polaris,同时也提供 SPI 接口可自定义扩展实现

  • 中间件线程池管理:集成管理常用第三方组件的线程池,已集成 Tomcat、Jetty、Undertow、Dubbo、RocketMq、Hystrix、Grpc、Motan、Okhttp3、Brpc、Tars、SofaRpc、RabbitMq 等组件的线程池管理(调参、监控报警)

  • 轻量简单:基于 SpringBoot 实现,引入 starter,接入只需简单 4 步就可完成,顺利 3 分钟搞定

  • 多模式:参考 Tomcat 线程池提供了 IO 密集型场景使用的 EagerDtpExecutor 线程池

  • 兼容性:JUC 普通线程池和 Spring 中的 ThreadPoolTaskExecutor 也可以被框架监控,@Bean 定义时加 @DynamicTp 注解即可

  • 可靠性:框架提供的线程池实现 Spring 生命周期方法,可以在 Spring 容器关闭前尽可能多的处理队列中的任务

  • 高可扩展:框架核心功能都提供 SPI 接口供用户自定义个性化实现(配置中心、配置文件解析、通知告警、监控数据采集、任务包装等等)

  • 线上大规模应用:参考美团线程池实践,美团内部已经有该理论成熟的应用经验

美团线程池实践:

https://tech.meituan.com/2020/04/02/java-pooling-pratice-in-meituan.html

三、架构设计

DynamicTp框架功能大体可以分为以下几个模块:

  1. 配置变更监听模块

  2. 线程池管理模块

  3. 监控模块

  4. 通知告警模块

  5. 三方组件线程池管理模块

四、接入步骤 

4.1 引入依赖

在pom.xml中引入下述依赖:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.3.RELEASE</version><relativePath/></parent><groupId>com.bc</groupId><artifactId>demo</artifactId><version>0.0.1-SNAPSHOT</version><name>demo</name><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version></properties><dependencyManagement><dependencies><!-- 整合Spring Boot--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>2.1.3.RELEASE</version><type>pom</type><scope>import</scope></dependency><!-- 整合Spring Cloud --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>Greenwich.SR3</version><type>pom</type><scope>import</scope></dependency><!-- 整合Spring Cloud Alibaba --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>2.1.2.RELEASE</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.hibernate</groupId><artifactId>hibernate-validator</artifactId><version>6.0.1.Final</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId></dependency><dependency><groupId>org.dromara.dynamictp</groupId><artifactId>dynamic-tp-spring-cloud-starter-nacos</artifactId><version>1.1.7</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project>

这里有一个可能需要关注的问题,就是曾经在引入了上述依赖后,启动项目会报下述错误:

Caused by: java.lang.NoClassDefFoundError: com/fasterxml/jackson/databind/json/JsonMapper

解决方法:就是关于jackson的版本依赖低了,将其版本设定为2.10.0版本就可以解决这个问题 

<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.10.0</version>
</dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.10.0</version>
</dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId><version>2.10.0</version>
</dependency>

4.2 配置中心配置线程池实例 

采用nacos作为配置中心,nacos服务端的版本为v2.1.2(此处我是采用Docker进行搭建服务端),nacos客户端的版本在上述依赖引入中也是2.1.2版本。

第一步: 在nacos中创建一个新的命名空间local

新创建的命名空间local其命名空间ID为:322d6d5e-16bb-4f0d-846a-bbb1012eff92 

第二步:在配置管理的local命名空间下新增配置记录

新增配置的各个选项中,其Data ID为dtp_config,GROUP为DTP_SERVER_GROUP,描述为DTP动态线程池服务的配置分组,配置格式为YAML

其中Data ID的命令规则为:应用名-环境profile名.文件后缀

  • 应用名(Data ID前缀):默认为  ${spring.appliction.name}, 也可以使用${spring.cloud.nacos.config.prefix}来配置
  • 环境profile名:既${spring.profiles.active}指定的环境。  若不区分环境,则本内容既前面的中划线都可以不用存在。
  • 文件后缀:既SpringBoot中配置文件扩展名,也是Nacos中的配置格式。

上述yaml里面的配置内容如下所示: 

spring:dynamic:tp:enabled: true                               # 是否启用dynamictp,默认trueenabledBanner: true                        # 是否打印启动图标,默认为true表示打印,值为false表示不打印   enabledCollect: true                        # 是否开启监控指标采集,默认truecollectorTypes: micrometer,logging          # 监控数据采集器类型(logging | micrometer | internal_logging | JMX),默认micrometerlogPath: /home/logs/dynamictp/user-center/  # 监控日志数据路径,默认 ${user.home}/logs,采集类型非logging不用配置monitorInterval: 5                          # 监控时间间隔(报警检测、指标采集),默认5splatforms:                                  # 通知报警平台配置- platform: wechatplatformId: 1                            # 平台id,自定义urlKey: 3a700-127-4bd-a798-c53d8b69c     # webhook 中的 keyreceivers: test1,test2                   # 接受人企微账号- platform: dingplatformId: 2                            # 平台id,自定义urlKey: f80dad441fcd655438f4a08dcd6a     # webhook 中的 access_tokensecret: SECb5441fa6f375d5b9d21           # 安全设置在验签模式下才的秘钥,非验签模式没有此值receivers: 18888888888                   # 钉钉账号手机号- platform: larkplatformId: 3urlKey: 0d944ae7-b24a-40                 # webhook 中的 tokensecret: 3a750012874bdac5c3d8b69c         # 安全设置在签名校验模式下才的秘钥,非验签模式没有此值receivers: test1,test2                   # 接受人username / openid- platform: emailplatformId: 4receivers: 123456789@163.com            # 收件人邮箱,多个用逗号隔开executors:                               # 动态线程池配置,都有默认值,采用默认值的可以不配置该项,减少配置量- threadPoolName: dtpExecutor          # 线程池名称,必填threadPoolAliasName: 测试线程池        # 线程池别名,可选executorType: common                 # 线程池类型 common、eager、ordered、scheduled、priority,默认 commoncorePoolSize: 6                      # 核心线程数,默认为1maximumPoolSize: 8                   # 最大线程数,默认cpu核数queueCapacity: 2000                  # 队列容量,默认1024queueType: VariableLinkedBlockingQueue         # 任务队列,查看源码QueueTypeEnum枚举类,默认VariableLinkedBlockingQueuerejectedHandlerType: CallerRunsPolicy          # 拒绝策略,查看RejectedTypeEnum枚举类,默认AbortPolicykeepAliveTime: 60                              # 空闲线程等待超时时间,默认60threadNamePrefix: test                         # 线程名前缀,默认dtpallowCoreThreadTimeOut: false                  # 是否允许核心线程池超时,默认falsewaitForTasksToCompleteOnShutdown: true         # 参考spring线程池设计,优雅关闭线程池,默认trueawaitTerminationSeconds: 5                     # 优雅关闭线程池时,阻塞等待线程池中任务执行时间,默认3,单位(s)preStartAllCoreThreads: false                  # 是否预热所有核心线程,默认falserunTimeout: 0                                  # 任务执行超时阈值,单位(ms),默认0(不统计)queueTimeout: 0                                # 任务在队列等待超时阈值,单位(ms),默认0(不统计)taskWrapperNames: ["ttl", "mdc"]               # 任务包装器名称,继承TaskWrapper接口notifyEnabled: true                            # 是否开启报警,默认trueplatformIds: [4]                             # 报警平台id,不配置默认拿上层platforms配置的所有平台notifyItems:                     # 报警项,不配置自动会按默认值(查看源码NotifyItem类)配置(变更通知、容量报警、活性报警、拒绝报警、任务超时报警)- type: changeenabled: true- type: capacity               # 队列容量使用率,报警项类型,查看源码 NotifyTypeEnum枚举类enabled: truethreshold: 80                # 报警阈值,默认70,意思是队列使用率达到70%告警platformIds: [2]             # 可选配置,本配置优先级 > 所属线程池platformIds > 全局配置platformsinterval: 120                # 报警间隔(单位:s),默认120- type: liveness               # 线程池活性enabled: truethreshold: 80                # 报警阈值,默认 70,意思是活性达到70%告警- type: reject                 # 触发任务拒绝告警enabled: truethreshold: 100               # 默认阈值10- type: run_timeout            # 任务执行超时告警enabled: truethreshold: 5                 # 默认阈值10- type: queue_timeout          # 任务排队超时告警enabled: truethreshold: 100               # 默认阈值10

点击发布以后,在其配置管理列表中就会新增一条记录:

4.3 客户端的配置文件

在resources目录下新建一个名为application.yml的文件:

server:port: 10086spring:application:name: dtp-server

接着还需在resources目录下新建一个名为bootstrap.yml的文件(bootstrap.yml文件加载顺序先于application.yml): 

spring:cloud:nacos:discovery:server-addr:  127.0.0.1:28999namespace: 322d6d5e-16bb-4f0d-846a-bbb1012eff92config:server-addr: 127.0.0.1:28999namespace: 322d6d5e-16bb-4f0d-846a-bbb1012eff92group: DTP_SERVER_GROUP                           # 配置组(如果不指定,则默认为DEFAULT_GROUP)prefix: dtp_config                                # Data ID的前缀(如果不指定,则默认取 ${spring.appliction.name})file-extension: yaml                             # 指定文件后缀(如果不指定,则默认为properties),此处指定为yaml格式extension-configs:- dataId: dtp_config.yamlgroup: DTP_SERVER_GROUPrefresh: true                 # 必须配置,负责自动刷新不生效refresh-enabled: true                           # 如果在Nacos控制台界面中人工调整配置项的值,SpringBoot会立即自动取得最新值。因为Nacos客户端带自动刷新功能,可以通过配置 spring.cloud.nacos.config.refresh.enabled=false 来关闭自动刷新

至此关于这一步的操作算是已经完成了,接下来将说一下nacos的共享和常规配置文件相关的扩展内容。

spring.cloud.nacod.config.shared-configs:这是一个用于读取共享的配置文件的配置项,里面可以有多组配置。 在源码中有三个属性:data-id、group、refresh。

public static class Config {private String dataId;private String group;private boolean refresh;...
}

spring.cloud.nacod.config.extension-configs:在shared-configs之后加载,但是优先级大于shared-configs,一般用于单模块配置。shared-configs可以配置为项目共有配置,如redis配置,数据库链接等等。

spring:cloud:nacos:discovery:server-addr:  127.0.0.1:28999namespace: 322d6d5e-16bb-4f0d-846a-bbb1012eff92config:server-addr: 127.0.0.1:28999namespace: 322d6d5e-16bb-4f0d-846a-bbb1012eff92group: DTP_SERVER_GROUP                           # 配置组(如果不指定,则默认为DEFAULT_GROUP)prefix: dtp_config                                # Data ID的前缀(如果不指定,则默认取 ${spring.appliction.name})file-extension: yaml                              # 指定文件后缀(如果不指定,则默认为properties),此处指定为yaml格式# 用于共享的配置文件shared-configs:- data-id: common-mysql.yamlgroup: SPRING_CLOUD_EXAMPLE_GROUP- data-id: common-redis.yamlgroup: SPRING_CLOUD_EXAMPLE_GROUP- data-id: common-base.yamlgroup: SPRING_CLOUD_EXAMPLE_GROUP# 常规配置文件,优先级大于 shared-configs,在 shared-configs 之后加载extension-configs:- data-id: nacos-config-advanced.yamlgroup: SPRING_CLOUD_EXAMPLE_GROUPrefresh: true- data-id: nacos-config-base.yamlgroup: SPRING_CLOUD_EXAMPLE_GROUPrefresh: true		refresh-enabled: true

4.4  启动类添加@EnableDynamicTp注解

package com.example.demo;import org.dromara.dynamictp.core.spring.EnableDynamicTp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;@EnableDynamicTp
@EnableDiscoveryClient
@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);}}

4.5 使用DtpExecutor

第一种方式:使用@Resource 或 @Autowired 进行依赖注入 

package com.example.demo.controller;import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.dromara.dynamictp.core.executor.DtpExecutor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;import java.net.InetAddress;@Slf4j
@RefreshScope
@RestController
@RequestMapping("/demo")
public class DemoController {@Value("${spring.dynamic.tp.executors[0].corePoolSize}")String springDynamicTpExecutor0CorePoolSize;@Resourceprivate DtpExecutor dtpExecutor;@GetMapping("/select")public String select() throws Exception {log.info("executors[0]的核心线程数:{}",springDynamicTpExecutor0CorePoolSize);dtpExecutor.execute(() -> {log.info("开始执行任务");try {Thread.sleep(5000);} catch (Exception e) {e.printStackTrace();}log.info("结束执行任务");});JSONObject jsonObject = new JSONObject(true);jsonObject.put("IP", InetAddress.getLocalHost().getHostAddress());jsonObject.put("可用处理器数量", Runtime.getRuntime().availableProcessors());jsonObject.put("核心线程数", dtpExecutor.getCorePoolSize());jsonObject.put("最大线程数", dtpExecutor.getMaximumPoolSize());jsonObject.put("正在工作的线程数", dtpExecutor.getActiveCount());jsonObject.put("队列中的任务数", dtpExecutor.getQueue().size());jsonObject.put("已提交的任务总数", dtpExecutor.getTaskCount());return jsonObject.toString();}
}

第二种方式:通过 DtpRegistry.getDtpExecutor("name") 获取 

package com.example.demo.controller;import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.dromara.dynamictp.core.DtpRegistry;
import org.dromara.dynamictp.core.executor.DtpExecutor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.net.InetAddress;@Slf4j
@RefreshScope
@RestController
@RequestMapping("/demo")
public class DemoController {@Value("${spring.dynamic.tp.executors[0].corePoolSize}")String springDynamicTpExecutor0CorePoolSize;@GetMapping("/select")public String select() throws Exception {log.info("executors[0]的核心线程数:{}",springDynamicTpExecutor0CorePoolSize);DtpExecutor dtpExecutor = DtpRegistry.getDtpExecutor("dtpExecutor");dtpExecutor.execute(() -> {log.info("开始执行任务");try {Thread.sleep(5000);} catch (Exception e) {e.printStackTrace();}log.info("结束执行任务");});JSONObject jsonObject = new JSONObject(true);jsonObject.put("IP", InetAddress.getLocalHost().getHostAddress());jsonObject.put("可用处理器数量", Runtime.getRuntime().availableProcessors());jsonObject.put("核心线程数", dtpExecutor.getCorePoolSize());jsonObject.put("最大线程数", dtpExecutor.getMaximumPoolSize());jsonObject.put("正在工作的线程数", dtpExecutor.getActiveCount());jsonObject.put("队列中的任务数", dtpExecutor.getQueue().size());jsonObject.put("已提交的任务总数", dtpExecutor.getTaskCount());return jsonObject.toString();}
}

经过测试,不管是才有那种获取方式都可以实现线程池的动态修改和实时更新! 

五、通知报警

触发报警阈值会推送相应报警消息(活性、容量、拒绝、任务等待超时、任务执行超时),且会高亮显示相应字段,如下图所示:

配置变更会推送通知消息,且会高亮变更的字段,如下图所示:

特别说明:在引入邮件推送时,这个还需要引入额外的依赖包,具体怎么做可以参考官方技术文档。 

六、监控 

目前框架提供了四种监控数据采集方式,通过 collectorTypes 属性配置监控指标采集类型,默认 Micrometer:

  • Logging:线程池指标数据会以 Json 格式输出到指定的日志文件里

  • Internal_logging:线程池指标数据会以 Json 格式输出到项目日志文件里

  • Micrometer:采用监控门面,通过引入相关 Micrometer 依赖采集到相应的存储平台里(如 Prometheus,InfluxDb...)

  • Endpoint:暴露 Endpoint 端点,可以通过 http 方式实时获取指标数据

相关文章:

轻量级动态可监控线程池 - DynamicTp

一、背景介绍 使用线程池ThreadPoolExecutor的过程中你是否有以下痛点呢&#xff1f; 代码中创建了一个 ThreadPoolExecutor&#xff0c;但是不知道那几个核心参数设置多少比较合适凭经验设置参数值&#xff0c;上线后发现需要调整&#xff0c;改代码重新发布服务&#xff0c…...

对于vsc中的vue命令 vue.json

打开vsc 然后在左下角有一个设置 2.点击用户代码片段 3.输入 vue.json回车 将此代码粘贴 &#xff08;我的不一定都适合&#xff09; { "vue2 template": { "prefix": "v2", "body": [ "<template>", " <…...

Spring Boot 官方不再支持 Spring Boot 的 2.x 版本!新idea如何创建java8项目

idea现在只能创建最少jdk17 使用 IDEA 内置的 Spring Initializr 创建 Spring Boot 新项目时&#xff0c;没有 Java 8 的选项了&#xff0c;只剩下了 > 17 的版本 是因为 Spring Boot 官方不再支持 Spring Boot 的 2.x 版本了&#xff0c;之后全力维护 3.x&#xff1b;而 …...

分享一个 ASP.NET Web Api 上传和读取 Excel的方案

前言 许多业务场景下需要处理和分析大量的数据&#xff0c;而 Excel 是业务人员常用的数据表格工具&#xff0c;因此&#xff0c;将 Excel 表格中内容上传并读取到网站&#xff0c;是一个很常见的功能&#xff0c;目前有许多成熟的开源或者商业的第三方库&#xff0c;比如 NPO…...

【算法实战】每日一题:将某个序列中内的每个元素都设为相同的值的最短次数(差分数组解法,附概念理解以及实战操作)

题目 将某个序列中内的每个元素都设为相同的值的最短次数 1.差分数组&#xff08;后面的减去前面的值存储的位置可以理解为中间&#xff09; 差分数组用于处理序列中的区间更新和查询问题。它存储序列中相邻元素之间的差值&#xff0c;而不是直接存储每个元素的值 怎么对某…...

EXCEL数据透视图中的日期字段,怎样自动分出年、季度、月的功能?

在excel里&#xff0c;这个果然是有个设置的地方&#xff0c;修改后就好了。 点击文件选项卡&#xff0c;选项&#xff0c;在高级里&#xff0c;将图示选项的勾选给取消&#xff0c;然后再创建数据透视表或透视图&#xff0c;日期就不会自动组合了&#xff1a; 这个选项只对新…...

【设计模式深度剖析】【1】【行为型】【模板方法模式】| 以烹饪过程为例加深理解

&#x1f448;️上一篇:结构型设计模式对比 文章目录 模板方法模式定义英文原话直译如何理解呢&#xff1f; 2个角色类图代码示例 应用优点缺点使用场景 示例解析&#xff1a;以烹饪过程为例类图代码示例 模板方法模式 模板方法模式&#xff08;Template Method Pattern&…...

JAVA:异步任务处理类CompletableFuture让性能提升一倍

一、前言 CompletableFuture 是 Java 8 引入的一个功能强大的类&#xff0c;用于异步编程。它表示一个可能尚未完成的计算的结果&#xff0c;你可以对其添加回调函数来在计算完成时执行某些操作。在 Spring Boot 应用中&#xff0c;CompletableFuture 可以用于提高应用的响应性…...

10Linux 进程管理学习笔记

Linux 进程管理 目录 文章目录 Linux 进程管理一.进程1.显示当前进程状态(ps)进程树(pstree)1.1实时显示进程信息(top)顶部概览信息&#xff1a;CPU 状态&#xff1a;内存状态&#xff1a;进程信息表头&#xff1a;进程列表&#xff1a;1.2(htop) 2.终止进程(kill)2.1通过名称…...

一些关于深度聚类以及部分对比学习的论文阅读笔记

目录 资料SwAV问题方法方法的创新点为什么有效有什么可以借鉴的地方聚类Multi-crop 代码 PCL代码 Feature Alignment and Uniformity for Test Time Adaptation代码 SimSiam 资料 深度聚类算法研究综述(很赞&#xff0c;从聚类方法和深度学习方法两个方面进行了总结&#xff0…...

【ARM-Linux篇】u-boot编译

一、u-boot简介 uboot是一种通用的引导加载程序&#xff0c;它可以用于多种嵌入式系统&#xff0c;支持多种操作系统&#xff0c;如Linux, Android,NetBSD等。uboot的主要作用是将操作系统内核从存储设备&#xff08;如Flash, SD卡等&#xff09;加载到内存中&#xff0c;并执…...

Lombok一文通

1、Lombok简介 作为java的忠实粉丝&#xff0c;但也不得不承认&#xff0c;java是一门比较啰嗦的语言&#xff0c;很多代码的编写远不如其他静态语言方便&#xff0c;更别说跟脚本语言比较了。 因此&#xff0c;lombok应运而生。 Lombok是一种工具库&#xff0c;它提供了一组…...

Seq2Seq模型:详述其发展历程、深远影响与结构深度剖析

Seq2Seq&#xff08;Sequence-to-Sequence&#xff09;模型是一种深度学习架构&#xff0c;专为处理从一个输入序列到一个输出序列的映射任务设计。这种模型最初应用于机器翻译任务&#xff0c;但因其灵活性和有效性&#xff0c;现已被广泛应用于自然语言处理&#xff08;NLP&a…...

公网如何访问内网?

公网和内网已经成为我们生活中不可或缺的存在。由于内网的安全性考虑&#xff0c;公网无法直接访问内网资源。如何实现公网访问内网呢&#xff1f;本文将介绍一种名为【天联】的私有通道技术&#xff0c;通过安全加密&#xff0c;保障数据传输的安全性。 【天联】私有通道技术 …...

手机定制开发_基于天玑900的5G安卓手机定制方案

手机定制方案基于联发科天玑900强劲旗舰八核2.4GHz处理器。这款处理器采用了6nm先进制程工艺&#xff0c;为用户带来了痛快淋漓的性能体验。不论是进行游戏还是日常娱乐&#xff0c;用户都能轻松驾驭。手机搭载了最新的Android 13操作系统&#xff0c;提高了数据读取的准确性&a…...

免费,C++蓝桥杯等级考试真题--第2级

C蓝桥杯等级考试真题–第2级...

panic 、asset、crash 的含义和区别

在编程中&#xff0c;“panic” 和 “assert” 都是用于处理错误和异常情况的机制&#xff0c;但在不同的编程语言和框架中有一些区别。 panic&#xff1a; 含义&#xff1a;通常表示程序发生了无法恢复的错误或异常情况&#xff0c;需要立即终止程序的执行。 用法&#xff1…...

解决Windows 10通过SSH连接Ubuntu 20.04时的“Permission Denied”错误

在使用SSH连接远程服务器时&#xff0c;我们经常可能遇到各种连接错误&#xff0c;其中“Permission denied, please try again”是较为常见的一种。本文将分享一次实际案例的解决过程&#xff0c;帮助你理解如何排查并解决这类问题。 问题描述 在尝试从Windows 10系统通过SS…...

Windows 下 PostgreSQL 图形化界面安装、配置详解

相信大家对PostgreSQL都不陌生吧&#xff0c;自从MySQL被Oracle所控制后&#xff0c;PostgreSQL就成为了国内去O的首选数据库了&#xff0c;并且PostgreSQL目前不受任何商业公司控制&#xff0c;所以国内很多厂商都是基于PostgreSQL做二次开发来实现数据库自主可控的目标(国内很…...

曾巩,散文的艺术与哲思

曾巩&#xff0c;字子固&#xff0c;世称南丰先生&#xff0c;南丰&#xff08;今江西&#xff09;人&#xff0c;生于北宋真宗天禧三年&#xff08;公元1019年&#xff09;&#xff0c;卒于北宋元丰六年&#xff08;公元1083年&#xff09;&#xff0c;享年64岁。他是中国北宋…...

【SpringBoot】怎么在一个大的SpringBoot项目中创建多个小的SpringBoot项目,从而形成子父依赖

父子项目工程创建 步骤 先创建父项目 具体操作步骤请看本文章&#xff1a;使用maven工程创建spring boot项目 创建子项目 file- project structure module–new module 剩下步骤请看创建父工程时的操作使用maven工程创建spring boot项目 应用 确认即可 之后创建启动类…...

vue3组件通信与props

title: vue3组件通信与props date: 2024/5/31 下午9:00:57 updated: 2024/5/31 下午9:00:57 categories: 前端开发 tags: Vue3组件Props详解生命周期数据通信模板语法Composition API单向数据流 Vue 3 组件基础 在 Vue 3 中&#xff0c;组件是构建用户界面的基本单位&#…...

并发和异步编程:详细概述

01 Concurrency and Asynchronous Programming: a Detailed Overview 并发和异步编程:详细概述 Asynchronous programming is one of those topics many programmers find confusing. You come to the point when you think you’ve got it, only to later realize that the …...

交易员摩拳擦掌,就在今年夏天,极端气候引爆商品?

有史以来最严重的高温炙烤下&#xff0c;从农业到能源到航运都可能受到严重负面影响&#xff0c;大宗商品市场波动将大幅加剧。 2024年有望成为有史以来最炎热的一年&#xff0c;随着北半球步入夏季&#xff0c;世界各地都将遭受由全球变暖造成的极端高温困扰。极端天气不仅给民…...

数据结构学习笔记

1. 数组 (Array) 定义 数组是一种线性数据结构&#xff0c;用于存储固定大小的相同类型元素集合。每个元素都有一个索引&#xff0c;用于快速访问。 特点 优点&#xff1a;访问速度快&#xff0c;通过索引直接访问O(1)时间复杂度。缺点&#xff1a;大小固定&#xff0c;插入…...

vscode导入自定义模块报错ModuleNotFoundError解决方案

问题描述 我的项目为great_gas_or_agents&#xff0c;目录结构如下&#xff1a; log_data_extract main.py math_algorithm 现在我运行main.py&#xff0c;报错&#xff1a;from math_algorithm.utils import parse_month_match_request&#xff0c;ModuleNotFoundError: No …...

go mod包管理与应用,常见错误排查方法

go mod包管理 go 中 包管理使用go mod 进行包管理 go mod init 项目名称 go mod init myproject_go生成的go.mod中有 module myproject_go 创建目录go_service 其下有两个go文件&#xff0c;go_request.go go_write.go . 根目录下有main.go入口文件。于是项目结构类似于&…...

数据结构作业

第1章 绪论 单选题 数据在计算机的存储器中表示时&#xff0c;逻辑上相邻的两个元素对应的物理地址也是相邻的&#xff0c;这种存储结构称之为________。 B. 顺序存储结构 算法指的是________。 D. 求解特定问题的指令有限序列 下面程序段的时间复杂度为&#xff1a;_______…...

项目纪实 | 版本升级操作get!GreatDB分布式升级过程详解

某客户项目现场&#xff0c;因其业务系统要用到数据库新版本中的功能特性&#xff0c;因此考虑升级现有数据库版本。在升级之前&#xff0c;万里数据库项目团队帮助客户在本地测试环境构造了相同的基础版本&#xff0c;导入部分生产数据&#xff0c;尽量复刻生产环境进行升级&a…...

富格林:应用正规技巧阻挠被骗

富格林悉知&#xff0c;随着如今入市现货黄金的朋友愈来愈多&#xff0c;不少投资者也慢慢开始重视起提高自身的正规投资技巧&#xff0c;希望能阻挠被骗更高效地在市场上获利。虽然目前黄金市场存在一定的受害风险&#xff0c;但只要投资者严格按照正规的交易规则来做单&#…...

【模型架构】学习RNN、LSTM、TextCNN和Transformer以及PyTorch代码实现

一、前言 在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;模型架构的不断发展极大地推动了技术的进步。从早期的循环神经网络&#xff08;RNN&#xff09;到长短期记忆网络&#xff08;LSTM&#xff09;、Transformer再到当下火热的Mamba&#xff08;放在下一节&a…...

【LeetCode】38.外观数列

外观数列 题目描述&#xff1a; 「外观数列」是一个数位字符串序列&#xff0c;由递归公式定义&#xff1a; countAndSay(1) "1"countAndSay(n) 是 countAndSay(n-1) 的行程长度编码。 行程长度编码&#xff08;RLE&#xff09;是一种字符串压缩方法&#xff0c…...

如何解决Ubuntu中软件包安装时的404错误(无法安装gdb、cgddb等)

目录 问题描述 解决方法 1. 更新软件包列表 2. 使用--fix-missing选项 3. 更换软件源 4. 清理和修复包管理器 总结 在使用Ubuntu进行软件包安装时&#xff0c;有时可能会遇到404错误。这种错误通常是由于软件源中的某些包已经被移除或迁移到其他位置。本文将介绍几种解决…...

SpringBoot中MyBatisPlus的使用

MyBatis Plus 是 MyBatis 的增强工具&#xff0c;提供了许多强大的功能&#xff0c;简化了 MyBatis 的使用。下面是在 Spring Boot 中使用 MyBatis Plus 的步骤&#xff1a; 添加依赖&#xff1a;在 Maven 或 Gradle 的配置文件中添加 MyBatis Plus 的依赖。 配置数据源&#…...

前后端交互:axios 和 json;springboot 和 vue

vue 准备的 <template><div><button click"sendData">发送数据</button><button click"getData">接收</button><button click"refresh">刷新</button><br><ul v-if"questions&…...

前端技术专家岗(虚拟岗)

定位&#xff1a; 团队技术负责人、技术领导者&#xff1b;确保框架、工具的低门槛、高性能、可扩展&#xff1b; 素质要求&#xff1a; 具备架构设计能力&#xff1b;一个或者多个领域的技术专家&#xff1b;较为丰富的基础建设经验&#xff1b;项目管理能力、任务分解、协…...

redis windows环境下的部署安装

2024Redis windows安装、部署与环境变量 一、下载 Redis官网目前暂不支持Windows版本&#xff0c;只能从github中下载。 windows 64位系统下载redis路径&#xff1a;https://github.com/tporadowski/redis/releases&#xff0c;下载zip包。 目前Windows版本只更新到5.0的版本…...

大字体学生出勤记录系统网页HTML源码

源码介绍 上课需要一个个点名记录出勤情况&#xff0c;就借助AI制作了一个网页版学生出勤记录系统&#xff0c; 大字体显示学生姓名和照片&#xff0c;让坐在最后排学生也能看清楚&#xff0c;显示姓名同时会语音播报姓名&#xff0c; 操作很简单&#xff0c;先导入学生姓名…...

筛斗数据提取技术在企业成本预测中的应用

在当今的商业环境中&#xff0c;准确的成本预测对于企业的财务健康和战略规划至关重要。随着大数据和人工智能技术的飞速发展&#xff0c;数据提取技术已经成为企业进行成本预测的强大工具。本文将探讨数据提取技术如何帮助企业进行成本预测&#xff0c;并分析其对企业决策过程…...

enum编程入门:探索枚举类型的奥秘

enum编程入门&#xff1a;探索枚举类型的奥秘 在编程的世界里&#xff0c;enum&#xff08;枚举&#xff09;类型是一种特殊的数据类型&#xff0c;它允许我们为变量设置一组预定义的、有限的值。这种类型在很多编程语言中都得到了广泛的应用&#xff0c;为开发者提供了更加清…...

刷机 iPhone 进入恢复模式

文章目录 第 1 步&#xff1a;确保你有一台电脑&#xff08;Mac 或 PC&#xff09;第 2 步&#xff1a;将 iPhone 关机第 3 步&#xff1a;将 iPhone 置于恢复模式第 4 步&#xff1a;使用 Mac 或 PC 恢复 iPhone需要更多协助&#xff1f; 本文转载自&#xff1a;如果你忘记了 …...

计算属性和侦听器:为什么在某些情况下使用计算属性比使用methods更好,如何使用侦听器来监听数据的变化。

计算属性和methods的区别和使用场景 计算属性&#xff08;Computed properties&#xff09;是 Vue 中非常重要的一个功能&#xff0c;它有以下的优点&#xff1a; 数据缓存&#xff1a;计算属性基于它们的依赖进行缓存。只有在相关依赖发生变化时&#xff0c;才会重新求值。这…...

一文带你搞懂大事务的前因后果

引言 一文带你搞懂Spring事务上篇文章介绍了Spring事务相关内容&#xff0c;本文主要介绍业务开发中遇到的大事务问题。 https://github.com/WeiXiao-Hyy/blog 整理了Java,K8s,极客时间,设计模式等内容&#xff0c;欢迎Star! 什么是大事务 运行时间&#xff08;调用远程事务或…...

关系数据库:关系运算

文章目录 关系运算并&#xff08;Union&#xff09;差&#xff08;Difference&#xff09;交&#xff08;Intersection&#xff09;笛卡尔积&#xff08;Extended Cartesian Product&#xff09;投影&#xff08;projection&#xff09;选择&#xff08;Selection&#xff09;除…...

微信公众号开发(三):自动回复“你好”

上一篇做了服务器校验&#xff0c;但没有处理用户发来的消息&#xff0c;为了完成自动回复的功能&#xff0c;需要增加一些功能&#xff1a; 1、调整服务器校验函数&#xff1a; def verify_wechat(request):tokentokendatarequest.argssignaturedata.get(signature)timestamp…...

docker基本操作命令(3)

目录 1.Docker服务管理命令&#xff1a; 启动&#xff1a;systemctl start docker 停止&#xff1a;systemctl stop docker 重启&#xff1a;systemctl restart docker 开机自启&#xff1a;systemctl enable docker 查看docker版本&#xff1a; 2.镜像常用管理命令&…...

003 MySQL

文章目录 左外连接、右外连接 的区别where/having的区别执行顺序聚合 聚合函数MySQL约束事务一致性一致性的含义一致性在事务中的作用如何维护一致性 存储引擎 Innodb MyIsam区别事务的ACID属性数据库的隔离级别MySQL中的并发问题1. 锁等待和死锁2. 并发冲突3. 脏读、不可重复读…...

数据分析------统计学知识点(一)

1.在统计学中&#xff0c;均值分类有哪些&#xff1f; 算术均值&#xff1a;平均值&#xff0c;所有数值加总后除以数值的个数 几何均值&#xff1a;所有数值相乘后&#xff0c;再取其n次方根&#xff0c;n是数值的个数 调和均值&#xff1a;是数值倒数的算术均值的倒数 加…...

Apache Doris 基础 -- 数据表设计(分区分桶)

Versions: 2.1 本文档主要介绍了Doris的表创建和数据分区&#xff0c;以及表创建过程中可能遇到的问题和解决方案。 1、基本概念 在Doris中&#xff0c;数据以表的形式被逻辑地描述。 1.1 Row & Column 表由行和列组成: 行:表示用户数据的单行;列:用于描述一行数据中的…...

题目:求0—7所能组成的奇数个数。

题目&#xff1a;求0—7所能组成的奇数个数。 There is no nutrition in the blog content. After reading it, you will not only suffer from malnutrition, but also impotence. The blog content is all parallel goods. Those who are worried about being cheated should…...