2、Sentinel基本应用限流规则(2)

news2024/11/26 14:36:44

2.2.1 是什么
Sentinel 是阿里中间件团队开源的,面向分布式服务架构的轻量级高可用流量控制组件,主要以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度来帮助用户保护服务的稳定性。
在这里插入图片描述
2.2.2 基本概念
• 资源 (需要被保护的东西)

资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用的其它应用提供的服务,甚至可以是一段代码。在接下来的文档中,我们都会用资源来描述代码块。

只要通过 Sentinel API 定义的代码,就是资源,能够被 Sentinel 保护起来。大部分情况下,可以使用方法签名,URL,甚至服务名称作为资源名来标示资源。

资源的定义有两种,可以通过@SentinelResource(value=“doTest”)设置,如果没有设置的话,就默认取请求后面的一截

• 规则(限流的规则/熔断规则)

围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则。所有规则可以动态实时调整。

2.2.3 控制台
启动方式:

下载jar包,通过命令方式

在https://github.com/alibaba/Sentinel/releases下载对应版本的dashboard jar包,进入到该jar所在的目录,然后通过java命令运行该jar包即可:

java -Dserver.port=7777 -Dcsp.sentinel.dashboard.server=localhost:7777 -Dproject.name=sentinel-dashboard-1.8.0 -jar sentinel-dashboard-1.8.0.jar

访问地址:localhost:7777

默认账号和密码都是:sentinel

2.2.4 核心API使用
流量控制(Flow Control),原理是监控应用流量的QPS或并发线程数等指标,当达到指定阈值时对流量进行控制,避免系统被瞬时的流量高峰冲垮,保障应用高可用性。

下面写个简单的示例,看看如何使用Sentinel实现限流。

首先写个简单的订单查询接口,用于后续接口限流示例:

springboot-sentinel项目中demo01

引入Sentinel jar包:

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-core</artifactId>
    <version>1.8.0</version>
</dependency>

启动类:

@SpringBootApplication
public class SpringbootSentinelApplication {

    public static void main(String[] args) {
        initFlowQpsRule();
        SpringApplication.run(SpringbootSentinelApplication.class, args);
    }

    public static void initFlowQpsRule() {
        List<FlowRule> rules = new ArrayList<FlowRule>();
        FlowRule rule1 = new FlowRule();
        rule1.setResource("queryOrderInfo");
        // QPS控制在2以内
        rule1.setCount(2);
        // QPS限流
        rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
        rule1.setLimitApp("default");
        rules.add(rule1);
        FlowRuleManager.loadRules(rules);
    }
}
@Component
public class OrderQueryService {
    public String queryOrderInfo(String orderId) {
        System.out.println("获取订单信息:" + orderId);
        return "return OrderInfo :" + orderId;
    }
}
public class OrderControllser {
    @Autowired
    private OrderQueryService orderQueryService;

    @RequestMapping("/getOrder")
    @ResponseBody
    public String queryOrder1(@RequestParam("orderId") String orderId) {

        return orderQueryService.queryOrderInfo(orderId);
    }
}

正常情况下,调用OrderController中订单查询接口,会返回订单信息,如何控制接口访问的QPS在2以下呢?Sentienl限流提供了以下实现方式:

Sentienl如何使用 。

首先需要定义限流规则,比如对哪个接口进行限流,限制的QPS为多少,限制调用方app是什么等:

public void initFlowQpsRule() {
    List<FlowRule> rules = new ArrayList<FlowRule>();
    FlowRule rule1 = new FlowRule();
    rule1.setResource(KEY);
    // QPS控制在2以内
    rule1.setCount(2);
    // QPS限流
    rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
    rule1.setLimitApp("default");
    rules.add(rule1);
    FlowRuleManager.loadRules(rules);
}

限流实现方式有多种,这里只列出常见两种:

(1)限流实现方式一: 抛出异常的方式定义资源

此方式对代码侵入性较高,需要在接口调用的地方通过try-catch风格的API对代码进行包装:

/**
     * 限流实现方式一: 抛出异常的方式定义资源
     *
     * @param orderId
     * @return
     */
@RequestMapping("/getOrder2")
@ResponseBody
public String queryOrder2(@RequestParam("orderId") String orderId) {
    Entry entry = null;
    // 资源名
    String resourceName = "queryOrderInfo";
    try {
        // entry可以理解成入口登记
        entry = SphU.entry(resourceName);
        // 被保护的逻辑, 这里为订单查询接口
        return orderQueryService.queryOrderInfo(orderId);
    } catch (BlockException blockException) {
        // 接口被限流的时候, 会进入到这里
        blockException.printStackTrace();
        return "接口限流, 返回空";
    } finally {
        // SphU.entry(xxx) 需要与 entry.exit() 成对出现,否则会导致调用链记录异常
        if (entry != null) {
            entry.exit();
        }
    }
}

测试,当QPS>2时,接口返回:
在这里插入图片描述

我们可以在日志 ~/logs/csp/${appName}-metrics.log.xxx 里看到下面的输出:

C:\Users\gupao-jingtian\logs\csp

时间戳|格式化的时间戳|资源名|通过的请求|被拒绝的请求|成功数量|异常数量|rt平均响应时间
1600608724000|2020-09-20 21:32:04|helloWorld|5|6078|5|0|5|0|0|0
1600608725000|2020-09-20 21:32:05|helloWorld|5|32105|5|0|0|0|0|0
1600608726000|2020-09-20 21:32:06|helloWorld|5|41084|5|0|0|0|0|0
1600608727000|2020-09-20 21:32:07|helloWorld|5|72211|5|0|0|0|0|0
1600608728000|2020-09-20 21:32:08|helloWorld|5|60828|5|0|0|0|0|0
1600608729000|2020-09-20 21:32:09|helloWorld|5|41696|5|0|0|0|0|0

在这里插入图片描述
(2)限流实现方式二: 注解方式定义资源

上述通过try-catch风格的API可以实现限流,但是对代码侵入性太高,推荐使用注解的方式来实现。下文若不做注明,默认都会采用注解的方式实现。

关于注解的使用见:Sentinel注解使用

首先需要引入支持注解的jar包:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

在接口OrderQueryService中,使用注解实现订单查询接口的限流:

/**
 * 订单查询接口, 使用Sentinel注解实现限流
 *
 * @param orderId
 * @return
 */
@SentinelResource(value = "queryOrderInfo3", blockHandler = "handleFlowQpsException",
        fallback = "queryOrderInfo3Fallback")
public String queryOrderInfo3(String orderId) {

    // 模拟接口运行时抛出代码异常
    if ("000".equals(orderId)) {
        throw new RuntimeException();
    }

    System.out.println("获取订单信息:" + orderId);
    return "return OrderInfo3 :" + orderId;
}

/**
 * 订单查询接口抛出限流或降级时的处理逻辑
 *
 * 注意: 方法参数、返回值要与原函数保持一致
 * @return
 */
public String handleFlowQpsException(String orderId, BlockException e) {
    e.printStackTrace();
    return "handleFlowQpsException for queryOrderInfo3: " + orderId;
}

/**
 * 订单查询接口运行时抛出的异常提供fallback处理
 *
 * 注意: 方法参数、返回值要与原函数保持一致
 * @return
 */
public String queryOrderInfo3Fallback(String orderId, Throwable e) {
    return "fallback queryOrderInfo3: " + orderId;
}

• blockHandler = "handleFlowQpsException"用来处理Sentinel 限流/熔断等错误;

• fallback = "queryOrderInfo2Fallback"用来处理接口中业务代码所有异常(如业务代码异常、sentinel限流熔断异常等);注:以上两种处理方法中方法名、参数都需与受保护的函数保持一致。

测试:

/**
 * 限流实现方式二: 注解定义资源
 *
 * @param orderId
 * @return
 */
@RequestMapping("/getOrder3")
@ResponseBody
public String queryOrder3(@RequestParam("orderId") String orderId) {
    return orderQueryService.queryOrderInfo3(orderId);
}

2.2.5 流量控制
流量控制在网络传输中是一个常用的概念,它用于调整网络包的发送数据。然而,从系统稳定性角度考虑,在处理请求的速度上,也有非常多的讲究。任意时间到来的请求往往是随机不可控的,而系统的处理能力是有限的。我们需要根据系统的处理能力对流量进行控制。Sentinel 作为一个调配器,可以根据需要把随机的请求调整成合适的形状,如下图所示:
在这里插入图片描述
流量控制有以下几个角度:

• 并发数

• QPS

• 资源的调用关系

不管是什么方式,流控的核心原理是,监控应用流量的QPS或者并发线程数这些指标,去判断指标的阈值来实现对流量的控制,防止瞬时流高峰流量导致系统被压垮,从而保证系统的高可用性。

在Sentinel中,限流的直接表现形式是,在执行Entry nodeA = SphU.entry(resourceName)的时候抛出FlowException异常。FlowException是 BlockException的子类,您可以捕捉BlockException来自定义被限流之后的处理逻辑。

同一个资源可以创建多条限流规则。 FlowSlot 会对该资源的所有限流规则依次遍历,直到有规则触发限流或者所有规则遍历完毕。

一条限流规则主要由下面几个因素组成,我们可以组合这些元素来实现不同的限流效果:

• resource :资源名,即限流规则的作用对象

• count : 限流阈值

• grade : 限流阈值类型(QPS 或并发线程数)

• limitApp : 流控针对的调用来源,若为 default 则不区分调用来源

• default:表示不区分调用者,来自任何调用者的请求都将进行限流统计。如果这个资源名的调用总和超过了这条规则定义的阈值,则触发限流。

• {some_origin_name}:表示针对特定的调用者,只有来自这个调用者的请求才会进行流量控制。例如 NodeA 配置了一条针对调用者caller1的规则,那么当且仅当来自 caller1 对 NodeA 的请求才会触发流量控制。

• other:表示针对除 {some_origin_name} 以外的其余调用方的流量进行流量控制。例如,资源NodeA配置了一条针对调用者 caller1 的限流规则,同时又配置了一条调用者为 other 的规则,那么任意来自非 caller1 对 NodeA 的调用,都不能超过 other 这条规则定义的阈值。

• 同一个资源名可以配置多条规则,规则的生效顺序为:{some_origin_name} > other > default

• strategy : 调用关系限流策略

• controlBehavior : 流量控制效果(直接拒绝、Warm Up、匀速排队)

通过这个地址,可以查看实时的统计信息: http://localhost:8719/cnode?id=doTest

• thread: 代表当前处理该资源的并发数;

• pass: 代表一秒内到来到的请求;

• blocked: 代表一秒内被流量控制的请求数量;

• success: 代表一秒内成功处理完的请求;

• total: 代表到一秒内到来的请求以及被阻止的请求总和;

• RT: 代表一秒内该资源的平均响应时间;

• 1m-pass: 则是一分钟内到来的请求;

• 1m-block: 则是一分钟内被阻止的请求;

• 1m-all: 则是一分钟内到来的请求和被阻止的请求的总和;

• exception: 则是一秒内业务本身异常的总和。

2.2.5.1 并发线程数
并发数控制用于保护业务线程池不被慢调用耗尽。例如,当应用所依赖的下游应用由于某种原因导致服务不稳定、响应延迟增加,对于调用者来说,意味着吞吐量下降和更多的线程数占用,极端情况下甚至导致线程池耗尽。为应对太多线程占用的情况,业内有使用隔离的方案,比如通过不同业务逻辑使用不同线程池来隔离业务自身之间的资源争抢(线程池隔离)。这种隔离方案虽然隔离性比较好,但是代价就是线程数目太多,线程上下文切换的 overhead 比较大,特别是对低延时的调用有比较大的影响。Sentinel 并发控制不负责创建和管理线程池,而是简单统计当前请求上下文的线程数目(正在执行的调用数目),如果超出阈值,新的请求会被立即拒绝,效果类似于信号量隔离。并发数控制通常在调用端进行配置。

2.2.5.2 QPS流量
当 QPS 超过某个阈值的时候,则采取措施进行流量控制。流量控制的效果包括以下几种:直接拒绝、Warm Up、匀速排队。对应 FlowRule 中的 controlBehavior 字段。

2.2.5.3 基于调用关系
调用关系包含调用方和被调用方,一个方法有可能会调用其他方法,形成一个调用链,所谓的调用关系限流,就是根据不同的调用纬度来触发流量控制。

• 根据调用方限流

• 根据调用链路入口限流

• 具有关系的资源流量控制

2.2.5.3.1 根据调用方限流
很多场景下,根据调用方来限流也是非常重要的。比如有两个服务 A 和 B 都向 Service Provider 发起调用请求,我们希望只对来自服务 B 的请求进行限流,则可以设置限流规则的 limitApp 为服务 B 的名称。Sentinel Dubbo Adapter 会自动解析 Dubbo 消费者(调用方)的 application name 作为调用方名称(origin),在进行资源保护的时候都会带上调用方名称。若限流规则未配置调用方(default),则该限流规则对所有调用方生效。若限流规则配置了调用方则限流规则将仅对指定调用方生效。

所谓调用方限流,就是根据请求来源进行流量控制,我们可以设置limitApp属性来配置来源信息,它有三个选项:

• default :表示不区分调用者,来自任何调用者的请求都将进行限流统计。如果这个资源名的调用总和超过了这条规则定义的阈值,则触发限流。

• {some_origin_name} :表示针对特定的调用者,只有来自这个调用者的请求才会进行流量控制。例如 NodeA 配置了一条针对调用者 caller1 的规则,那么当且仅当来自 caller1 对NodeA 的请求才会触发流量控制。

• other :表示针对除 {some_origin_name} 以外的其余调用方的流量进行流量控制。例如,资源 NodeA 配置了一条针对调用者 caller1 的限流规则,同时又配置了一条调用者为 other 的规则,那么任意来自非 caller1 对 NodeA 的调用,都不能超过 other 这条规则定义的阈值。

对于同一个资源,可以配置多条规则,规则的生效顺序为: {some_origin_name} > other >default

2.2.5.3.2 根据调用链路入口限流
一个被限流的保护方法,可能来自于不同的调用链路,比如针对资源NodeA,入口 Entrance1 和Entrance2的请求都调用到了资源 NodeA ,Sentinel 允许只根据某个入口的统计信息对资源限流。比如我们可以设置 strategy 为 RuleConstant.STRATEGY_CHAIN ,同时设置 refResource 为Entrance1 来表示只有从入口 Entrance1 的调用才会记录到 NodeA 的限流统计当中,而不关心经Entrance2 到来的调用

在这里插入图片描述
2.2.5.3.3 具有关系的资源流量控制
当两个资源之间具有资源争抢或者依赖关系的时候,这两个资源便具有了关联。比如对数据库同一个字段的读操作和写操作存在争抢,读的速度过高会影响写得速度,写的速度过高会影响读的速度。如果放任读写操作争抢资源,则争抢本身带来的开销会降低整体的吞吐量。可使用关联限流来避免具有关联关系的资源之间过度的争抢,举例来说, read_db 和 write_db 这两个资源分别代表数据库读写,我们可以给 read_db 设置限流规则来达到写优先的目的:设置 strategy 为RuleConstant.STRATEGY_RELATE 同时设置 refResource 为 write_db 。这样当写库操作过于频繁时,读数据的请求会被限流

2.2.6 熔断降级
2.2.6.1 什么是熔断降级
除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。

由于调用关系的复杂性,如果调用链路中的某个资源不稳定,最终会导致请求发生堆积。Sentinel 熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联错误。当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断(默认行为是抛出 DegradeException)。
在这里插入图片描述
Sentinel 和 Hystrix 的原则是一致的: 当调用链路中某个资源出现不稳定,例如,表现为 timeout,异常比例升高的时候,则对这个资源的调用进行限制,并让请求快速失败,避免影响到其它的资源,最终产生雪崩的效果。

2.2.6.2 熔断降级设计理念
在限制的手段上,Sentinel 和 Hystrix 采取了完全不一样的方法。

Hystrix 通过线程池的方式,来对依赖(在我们的概念中对应资源)进行了隔离。这样做的好处是资源和资源之间做到了最彻底的隔离。缺点是除了增加了线程切换的成本,还需要预先给各个资源做线程池大小的分配。

Sentinel 对这个问题采取了两种手段:

• 通过并发线程数进行限制

和资源池隔离的方法不同,Sentinel 通过限制资源并发线程的数量,来减少不稳定资源对其它资源的影响。这样不但没有线程切换的损耗,也不需要您预先分配线程池的大小。当某个资源出现不稳定的情况下,例如响应时间变长,对资源的直接影响就是会造成线程数的逐步堆积。当线程数在特定资源上堆积到一定的数量之后,对该资源的新请求就会被拒绝。堆积的线程完成任务后才开始继续接收请求。

• 通过响应时间对资源进行降级

除了对并发线程数进行控制以外,Sentinel 还可以通过响应时间来快速降级不稳定的资源。当依赖的资源出现响应时间过长后,所有对该资源的访问都会被直接拒绝,直到过了指定的时间窗口之后才重新恢复。

下面就使用基于注解的方式实现Sentinel的熔断降级的demo。

springboot-sentinel项目中的demo02

2.2.7 控制策略
2.2.7.1 直接拒绝
直接拒绝( RuleConstant.CONTROL_BEHAVIOR_DEFAULT )方式是默认的流量控制方式,当QPS超过任意规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出 FlowException 。这种方式适用于对系统处理能力确切已知的情况下,比如通过压测确定了系统的准确水位时。

2.2.7.2 Warm Up
Warm Up( RuleConstant.CONTROL_BEHAVIOR_WARM_UP )方式,即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮

如下图所示,当前系统所能够处理的最大并发数是480,首先在最下面的标记位置,系统一直处于空闲状态,接着请求量突然直线升高,这个时候系统并不是直接将QPS拉到最大值,而是在一定时间内逐步增加阈值,而中间这段时间就是一个系统逐步预热的过车用。
在这里插入图片描述
2.2.7.3 匀速排队
匀速排队( RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER )方式会严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法。
在这里插入图片描述

这种方式主要用于处理间隔性突发的流量,例如消息队列。想象一下这样的场景,在某一秒有大量的请求到来,而接下来的几秒则处于空闲状态,我们希望系统能够在接下来的空闲期间逐渐处理这些请求,而不是在第一秒直接拒绝多余的请求。

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

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

相关文章

分享81个工作总结PPT,总有一款适合您

分享81个工作总结PPT&#xff0c;总有一款适合您 PPT下载链接&#xff1a;https://pan.baidu.com/s/13hyrlZo2GhRoQjI-6z31-w?pwd8888 提取码&#xff1a;8888 Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 学习知识费力气&#xff0c;收集整理更不易。知识付…

二叉搜索树专题1 二叉查找树的建立

题目&#xff1a; 样例&#xff1a; 输入 6 5 2 3 6 1 8 输出 5 2 1 3 6 8 思路&#xff1a; 二叉搜索树的建立&#xff0c;需要了解二叉搜索树的性质。 二叉搜索树的性质 左孩子结点&#xff1a; 比根节点小 右孩子结点&#xff1a; 比根节点大 根据所给的序列进行按序…

【数据结构】排序算法复杂度 及 稳定性分析 【图文详解】

排序算法总结 前言[ 一 ] 小数据基本排序算法&#xff08;1&#xff09;冒泡排序&#xff08;2&#xff09;直接插入排序 [ 二 ] &#xff08;由基本排序衍生的用作&#xff09;处理大数据处理排序&#xff08;1&#xff09;堆排序&#xff08;2&#xff09;希尔排序 [ 三 ] 大…

Leetcode-88 合并两个有序数组

使用内置排序函数&#xff0c;时间复杂度On^2 class Solution {public void merge(int[] nums1, int m, int[] nums2, int n) {int j0,im;while(j<n){nums1[i]nums2[j];}Arrays.sort(nums1);} }新建一个临时数组用于放排序后的元素&#xff0c;再将临时数组赋值给nums1&…

Technology strategy Pattern 学习笔记3-Creating the Strategy-Industry context

Creating the Strategy-Industry context 1 SWOT 1.1 create steps 1.与内部各方沟通 了解企业的人、流程和技术&#xff0c;包括与其它企业的不同了解哪些创新可以做竞争者及市场信息企业可以支撑的类似业务 按SWOT四象限分类&#xff0c;先做列表后放入象限 1.2 四象限…

C++ 代码实例:多项式除法简单计算工具

文章目录 前言代码仓库代码说明核心片段 结果总结参考资料作者的话 前言 C 代码实例&#xff1a;多项式除法简单计算工具。 代码仓库 yezhening/Programming-examples: 编程实例 (github.com)Programming-examples: 编程实例 (gitee.com) 代码 说明 由于代码篇幅较多&#…

AI:57-基于机器学习的番茄叶部病害图像识别

🚀 本文选自专栏:AI领域专栏 从基础到实践,深入了解算法、案例和最新趋势。无论你是初学者还是经验丰富的数据科学家,通过案例和项目实践,掌握核心概念和实用技能。每篇案例都包含代码实例,详细讲解供大家学习。 📌📌📌在这个漫长的过程,中途遇到了不少问题,但是…

linux之按键中断

查看原理图确认引脚 可以看到按键有两个&#xff0c;分别对应GPIO5_1和GPIO4_14 配置pinctrl&#xff0c;配置成GPIO模式 1.使用官方工具&#xff0c;配置下引脚 2.将生成的代码复制到设备树里 创建设备节点 生成二进制设备树文件 在工具链表下使用 make dtbs 或者使…

“宽带中国”工具变量—海拔标准差数据集

参照刘传明&#xff08;2020&#xff09;、金环&#xff08;2021&#xff09;、胡浩然&#xff08;2023&#xff09;等的做法&#xff0c;将地级市-海拔标准差数据&#xff0c;作为“宽带中国”试点政策的工具变量 ➤相关性&#xff1a;地形起伏度会影响网络基础设施建设&…

asp.net 创建docker容器

首先创建asp.net web api 创建完成后如下图 添加docker支持 添加docker支持 添加linux docker支持

SOEM源码解析——ecx_writeeeprom(写EEPROM)

0 工具准备 1.SOEM-master-1.4.0源码1 ecx_writeeeprom函数总览 /** Write EEPROM to slave bypassing cache.&#xff1a;绕过从站缓存写EEPROM数据* param[in] context context struct 句柄* param[in] slave Slave number 从站序号* param[in] eeproma (WORD) …

Voice vlan、ICMP、单臂路由、mux-vlan

目录 一&#xff0c;Voice VLAN Voice vlan配置命令 一&#xff0c;问&#xff1a;已知网络中一台服务器的IP地址&#xff0c;如何找到这太服务器在哪台交换机的哪个接口上​编辑 思路&#xff1a; 二&#xff0c;ICMP协议 三&#xff0c;ICMP案例分析​编辑 四&#xf…

学习c++的第十一天

目录 继承和派生 基类 & 派生类 访问控制和继承 派生类的构造函数 派生类的析构函数 继承类型 多继承 重载运算符和重载函数 函数重载 运算符重载 可重载运算符/不可重载运算符 运算符重载实例 继承和派生 先来说继承&#xff0c;这与现实生活中的继承意思差不…

2023年电工杯数学建模B题人工智能对大学生学习影响的评价求解全过程论文及程序

2023年电工杯数学建模 B题 人工智能对大学生学习影响的评价 原题再现&#xff1a; 人工智能简称AI&#xff0c;最初由麦卡锡、明斯基等科学家于1956年在美国达特茅斯学院开会研讨时提出。   2016年&#xff0c;人工智能AlphaGo 4:1战胜韩国围棋高手李世石&#xff0c;期后波…

【亚马逊云科技产品测评】活动征文|亚马逊云科技AWS之EC2详细测评

引言 &#xff08;授权声明&#xff1a;本篇文章授权活动官方亚马逊云科技文章转发、改写权&#xff0c;包括不限于在 Developer Centre, 知乎&#xff0c;自媒体平台&#xff0c;第三方开发者媒体等亚马逊云科技官方渠道&#xff09; 在当前的数字化时代&#xff0c;云服务已…

小饭店点餐系统,小餐馆点餐怎么方便,操作简单的酒店点单软件

小饭店点餐系统&#xff0c;小餐馆点餐怎么方便&#xff0c;操作简单的酒店点单软件 今天给大家分享是 佳易王酒店点餐管理系统软件V16.0版本&#xff0c;点餐界面如下图&#xff0c; 1、开台的桌子醒目显示&#xff0c;结账后或没有开台的桌子为灰色显示。 2、多种点餐方式…

Pytho入门教程之Python运行的三种方式

文章目录 一、交互式编程二、脚本式编程三、方式三关于Python技术储备一、Python所有方向的学习路线二、Python基础学习视频三、精品Python学习书籍四、Python工具包项目源码合集①Python工具包②Python实战案例③Python小游戏源码五、面试资料六、Python兼职渠道 一、交互式编…

AMD老电脑超频及性能提升方案及实施

收拾电子元件的时候找到了若干古董的CPU 其中有一个X3 440 是原来同学主板烧了之后给我的&#xff0c;我从网上配了AM2 昂达主板&#xff0c;然后又买了AMD兼容内存&#xff0c;组成了win7 64位电脑&#xff0c;用起来非常不错&#xff0c;我把硬件配置和升级过程说明下&#x…

C++对象模型

思考&#xff1a;对于实现平面一个点的参数化。C的class封装看起来比C的struct更加的复杂&#xff0c;是否意味着产生更多的开销呢&#xff1f; 实际上并没有&#xff0c;类的封装不会产生额外的开销&#xff0c;其实&#xff0c;C中在布局以及存取上的额外开销是virtual引起的…

unittest 通过loadTestsFromName执行多个测试case

这段代码是一个使用unittest模块编写的测试运行程序。它的主要功能是加载其他Python文件中的测试用例并运行这些测试用例。 首先&#xff0c;定义了一个主测试类MainTestCase&#xff0c;该类继承自unittest.TestCase。在这个类中&#xff0c;可以添加各种测试方法来测试不同的…