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

【Flink-scala】DataStream编程模型之窗口计算-触发器-驱逐器

DataStream API编程模型

1.【Flink-Scala】DataStream编程模型之数据源、数据转换、数据输出
2.【Flink-scala】DataStream编程模型之 窗口的划分-时间概念-窗口计算程序


文章目录

  • DataStream API编程模型
  • 前言
  • 1.触发器
    • 1.1 代码示例
  • 2.驱逐器
    • 2.1 代码示例
  • 总结


前言

本小节我想把 窗口计算中 的触发器和驱逐器讲完
然后开始水位线,延迟数据处理,状态编程等。


1.触发器

触发器决定了窗口何时由窗口计算函数进行处理。
(触发器就类比枪的扳机,触发后 计算函数开始计算,计算函数在【Flink-scala】DataStream编程模型之 窗口的划分-时间概念-窗口计算程序)

每个窗口分配器都带有一个默认触发器。如果默认触发器不能满足业务需求,就需要自定义触发器。

实现自定义触发器的方法很简单,只需要继承Trigger接口并实现它的方法即可。
Trigger接口有五种方法,允许触发器对不同的事件作出反应,
具体如下:

  1. onElement()方法:每个元素被添加到窗口时调用;
  2. onEventTime()方法:当一个已注册的事件时间计时器启动时调用;
  3. onProcessingTime()方法:当一个已注册的处理时间计时器启动时调用;
  4. onMerge()方法:与状态性触发器相关,当使用会话窗口时,两个触发器对应的窗口合并时,合并两个触发器的状态;
  5. clear()方法:执行任何需要清除的相应窗口。
    在这里插入图片描述

触发器通过 TriggerContext 来管理和检查状态。
在触发器中,我们通常会使用 状态 来记录窗口中的一些信息,如已处理的事件数量或累计的值。这些状态决定了窗口是否应当触发计算。

触发器中的 TriggerResult 有几个重要的结果:

CONTINUE:表示窗口继续等待更多的事件,不触发计算。
FIRE:表示触发窗口计算并输出结果。
PURGE:表示删除某些数据,通常在某些特殊场景下使用。

1.1 代码示例

假设股票价格数据流连续不断到达系统,现在需要对到达的数据进行监控,每到达5条数据就触发计算。实现该功能的代码如下:

import java.util.Calendar
import org.apache.flink.api.common.functions.ReduceFunction
import org.apache.flink.api.common.state.ReducingStateDescriptor
import org.apache.flink.streaming.api.TimeCharacteristic
import org.apache.flink.streaming.api.functions.source.RichSourceFunction
import org.apache.flink.streaming.api.functions.source.SourceFunction.SourceContext
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.api.scala.StreamExecutionEnvironment
import org.apache.flink.streaming.api.windowing.time.Time
import org.apache.flink.streaming.api.windowing.triggers.{Trigger, TriggerResult}
import org.apache.flink.streaming.api.windowing.windows.TimeWindow
import scala.util.Randomcase class StockPrice(stockId:String,timeStamp:Long,price:Double)object TriggerTest {def main(args: Array[String]) {//创建执行环境val env = StreamExecutionEnvironment.getExecutionEnvironment//设置程序并行度env.setParallelism(1)//设置为处理时间env.setStreamTimeCharacteristic(TimeCharacteristic.ProcessingTime)//创建数据源,股票价格数据流val source = env.socketTextStream("localhost", 9999)//指定针对数据流的转换操作逻辑val stockPriceStream = source.map(s => s.split(",")).map(s=>StockPrice(s(0).toString,s(1).toLong,s(2).toDouble))val sumStream = stockPriceStream.keyBy(s => s.stockId).timeWindow(Time.seconds(50)).trigger(new MyTrigger(5)).reduce((s1, s2) => StockPrice(s1.stockId,s1.timeStamp, s1.price + s2.price))//打印输出sumStream.print()//程序触发执行env.execute("Trigger Test")}class MyTrigger extends Trigger[StockPrice, TimeWindow] {//触发计算的最大数量private var maxCount: Long = _//记录当前数量的状态
private lazy val countStateDescriptor: ReducingStateDescriptor[Long] = new ReducingStateDescriptor[Long]("counter", new Sum, classOf[Long])def this(maxCount: Int) {this()this.maxCount = maxCount      
}override def onProcessingTime(time: Long, window: TimeWindow, ctx: Trigger.TriggerContext): TriggerResult = {TriggerResult.CONTINUE
}override def onEventTime(time: Long, window: TimeWindow, ctx: Trigger.TriggerContext): TriggerResult = {TriggerResult.CONTINUE
} override def onElement(element: StockPrice, timestamp: Long, window: TimeWindow, ctx: Trigger.TriggerContext): TriggerResult = {val countState = ctx.getPartitionedState(countStateDescriptor)//计数状态加1countState.add(1L)      if (countState.get() >= this.maxCount) {//达到指定指定数量       //清空计数状态countState.clear()//触发计算        TriggerResult.FIRE} else {TriggerResult.CONTINUE}}//窗口结束时清空状态override def clear(window: TimeWindow, ctx: Trigger.TriggerContext): Unit = {println("窗口结束时清空状态")ctx.getPartitionedState(countStateDescriptor).clear()}//更新状态为累加值class Sum extends ReduceFunction[Long] {override def reduce(value1: Long, value2: Long): Long = value1 + value2} }
}

注意 这一行代码:

val sumStream = stockPriceStream.keyBy(s => s.stockId).timeWindow(Time.seconds(50)).trigger(new MyTrigger(5)).reduce((s1, s2) => StockPrice(s1.stockId,s1.timeStamp, s1.price + s2.price))

在该代码中,MyTrigger 是一个自定义触发器,它控制在窗口中积累一定数量的事件后触发计算。

具体来说,窗口中的数据会根据 StockPrice 的数量来决定是否触发计算,而不是依赖于时间 。

接下来分析代码,

def this(maxCount: Int) {this()this.maxCount = maxCount      
}

这是它的主构造函数,它接受一个 maxCount 参数,表示在触发器中窗口内允许的最大元素数量。也就是说,窗口中的元素数达到 maxCount 时,触发器会触发计算(即调用 TriggerResult.FIRE)。
.trigger(new MyTrigger(5))表示创建一个 MyTrigger 的实例,并传入一个 maxCount 为 5 的参数,意思是窗口中最大允许 5 个元素,达到该数量后,窗口会触发计算。

private lazy val countStateDescriptor: ReducingStateDescriptor[Long] = new ReducingStateDescriptor[Long]("counter", new Sum, classOf[Long])

lazy:表示这是一个延迟初始化的变量。只有在第一次使用 countStateDescriptor 时,才会初始化它。这在性能优化上有作用,避免了不必要的初始化开销。

ReducingStateDescriptor 是 Flink 提供的一个状态描述符,它用于定义一个可减少的状态。这个状态会随着事件的到来不断累积,并且可以执行自定义的聚合操作。在 ReducingStateDescriptor 中,状态值的更新是通过 ReduceFunction 来实现的。

在这里,ReducingStateDescriptor[Long] 定义了一个状态,它的值是 Long 类型,并且该状态将执行 聚合操作(即对 Long 类型的值进行合并)。

ReducingStateDescriptor 的构造函数接受三个参数:

1.状态名称:“counter”
这是该状态的名称,用于在 Flink 的状态后端存储中标识该状态。

2.聚合操作:new Sum
这是一个 ReduceFunction 的实例,它定义了如何合并状态。在这个例子中,Sum 类是一个自定义的 ReduceFunction,用于对 Long 类型的值进行加法操作。

3.状态类型:classOf[Long]
这是状态的类型。classOf[Long] 表示状态值的类型是 Long,用于在 Flink 的状态管理中描述状态类型。

ClassOf(Long)这是 Scala 反射机制的语法,用于获取 Long 类型的 Class 对象。它在这里用于指定状态值的类型,以便 Flink 的状态管理能够正确地处理状态。

接下来的几个方法**TriggerResult.CONTINUE* 表示继续,不触发计算。
接下来是onElement方法

val countState = ctx.getPartitionedState(countStateDescriptor)

然后计数器+1,加到5就触发。
看是否到达maxcount。到达就触发,不到达就不触发,

自己的疑惑:才开始看代码的时候我一直纠结ctx( ctx.getPartitionedState(countStateDescriptor))这是从哪里来的,这个是

org.apache.flink.streaming.api.windowing.triggers.Trigger

下面的实例化对象,直接使用即可。

代码最后:
Sum类:它的作用是在状态更新时执行对状态的累加操作。

为什么用 Sum 作为累加器?

由于我们在 Trigger 中的 onElement 方法使用了 ctx.getPartitionedState(countStateDescriptor) 来获取一个 ReducingState(累加状态),这个状态将会不断地被更新,每次一个新元素进入时,都会触发 reduce 操作。

Sum 类就是定义了如何对这个 ReducingState 状态进行累加操作。
ReduceFunction 提供了累加器的逻辑,这样当多个元素进来时,value1 和 value2 就会被相加,最终在窗口中保持一个累积的状态。

2.驱逐器

学完上面的,学个单词:Evictor
在这里插入图片描述
驱逐器是Flink窗口机制的一个可选择组件。

驱逐 汉语意思就是 赶走,作用就是对进入窗口前后的数据进行驱逐(就是不接收,不要,你走 )

Flink内部实现了三种驱逐器,包括CountEvictor、DeltaEvictor和TimeEvictor。

三种驱逐器的功能如下:
CountEvictor:保持在窗口中具有固定数量的记录,将超过指定大小的数据在窗口计算之前删除;

DeltaEvictor:使用DeltaFunction和一个阈值,来计算窗口缓冲区中的最后一个元素与其余每个元素之间的差值,并删除差值大于或等于阈值的元素;

TimeEvictor:以毫秒为单位的时间间隔(interval)作为参数,对于给定的窗口,找到元素中的最大的时间戳max_ts,并删除时间戳小于max_ts - interval的所有元素。

在使用窗口函数之前被逐出的元素将不被处理。
默认情况下,所有内置的驱逐器在窗口函数之前使用。

和触发器一样,用户也可以通过实现Evictor接口完成自定义的驱逐器。
自定义驱逐器时,需要复写Evictor接口的两个方法:
evictBefore()和evictAfter()。
其中,evictBefore()方法定义数据在进入窗口函数计算之前执行驱逐操作的逻辑,
evictAfter()方法定义数据在进入窗口函数计算之后执行驱逐操作的逻辑。

2.1 代码示例

这个代码在做的事:统计窗口内股票价的平均值,并删除小于0的记录

import java.time.Duration
import java.util
import org.apache.flink.api.common.eventtime.{SerializableTimestampAssigner, WatermarkStrategy}
import org.apache.flink.streaming.api.TimeCharacteristic
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.api.scala.StreamExecutionEnvironment
import org.apache.flink.streaming.api.scala.function.ProcessWindowFunction
import org.apache.flink.streaming.api.windowing.evictors.Evictor
import org.apache.flink.streaming.api.windowing.time.Time
import org.apache.flink.streaming.api.windowing.windows.TimeWindow
import org.apache.flink.streaming.runtime.operators.windowing.TimestampedValue
import org.apache.flink.util.Collectorcase class StockPrice(stockId:String,timeStamp:Long,price:Double)
object EvictorTest {def main(args: Array[String]) {//设置执行环境val env = StreamExecutionEnvironment.getExecutionEnvironment//设置程序并行度env.setParallelism(1)//设置为处理时间env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)//创建数据源,股票价格数据流val source = env.socketTextStream("localhost", 9999)//指定针对数据流的转换操作逻辑val stockPriceStream = source.map(s => s.split(",")).map(s=>StockPrice(s(0).toString,s(1).toLong,s(2).toDouble))val sumStream = stockPriceStream.assignTimestampsAndWatermarks(WatermarkStrategy//为了测试方便,这里把水位线设置为0.forBoundedOutOfOrderness[StockPrice](Duration.ofSeconds(0)).withTimestampAssigner(new SerializableTimestampAssigner[StockPrice] {override def extractTimestamp(element: StockPrice, recordTimestamp: Long): Long = element.timeStamp})).keyBy(s => s.stockId).timeWindow(Time.seconds(3)).evictor(new MyEvictor()) //自定义驱逐器.process(new MyProcessWindowFunction())  //自定义窗口计算函数//打印输出sumStream.print() //程序触发执行 env.execute("Evictor Test")}class MyEvictor() extends Evictor[StockPrice, TimeWindow] {override def evictBefore(iterable: java.lang.Iterable[TimestampedValue[StockPrice]], i: Int, w: TimeWindow, evictorContext: Evictor.EvictorContext): Unit = {val ite: util.Iterator[TimestampedValue[StockPrice]] = iterable.iterator()while (ite.hasNext) {val elment: TimestampedValue[StockPrice] = ite.next()println("驱逐器获取到的股票价格:" + elment.getValue().price)//模拟去掉非法参数数据if (elment.getValue().price <= 0) {println("股票价格小于0,删除该记录")ite.remove()}}} 
override def evictAfter(iterable: java.lang.Iterable[TimestampedValue[StockPrice]], i: Int, w: TimeWindow, evictorContext: Evictor.EvictorContext): Unit = {
//不做任何操作}}class MyProcessWindowFunction extends ProcessWindowFunction[StockPrice, (String, Double), String, TimeWindow] {// 一个窗口结束的时候调用一次(一个分组执行一次),不适合大量数据,全量数据保存在内存中,会造成内存溢出override def process(key: String, context: Context, elements: Iterable[StockPrice], out: Collector[(String, Double)]): Unit = {// 聚合,注意:整个窗口的数据保存到Iterable,里面有很多行数据var sumPrice = 0.0;elements.foreach(stock => {sumPrice = sumPrice + stock.price})out.collect(key, sumPrice/elements.size)}}
}

myEvictor 是我们自定义的驱逐器类,它实现了 Evictor[StockPrice, TimeWindow] 接口.
在Evictor类中定义了before和after两个方法。
这着重看before,after没做什么。

override def evictBefore(iterable: java.lang.Iterable[TimestampedValue[StockPrice]], i: Int, w: TimeWindow, evictorContext: Evictor.EvictorContext): Unit = {val ite: util.Iterator[TimestampedValue[StockPrice]] = iterable.iterator()while (ite.hasNext) {val elment: TimestampedValue[StockPrice] = ite.next()println("驱逐器获取到的股票价格:" + elment.getValue().price)if (elment.getValue().price <= 0) {println("股票价格小于0,删除该记录")ite.remove()}}

参数的迭代器里,每个元素都是TimestampedValue[StockPrice]。
i表示要处理的数据量。
evictorContext:这是 Evictor.EvictorContext 类型,它提供了访问驱逐器上下文的接口。在此方法中并未使用,通常它可以用于管理驱逐操作的状态或者提供更多的上下文信息。
while里面的代码就不解释啦。

这里的参数太长,且陌生,多解释一下。
在窗口中运行输入

stock_1,1602031567000,8
stock_1,1602031568000,-4
stock_1,1602031569000,3
stock_1,1602031570000,-8
stock_1,1602031571000,9
stock_1,1602031572000,10

输出后的结果是:

驱逐器获取到的股票价格:8.0
驱逐器获取到的股票价格:-4.0
股票价格小于0,删除该记录
(stock_1,8.0)
驱逐器获取到的股票价格:3.0
驱逐器获取到的股票价格:-8.0
股票价格小于0,删除该记录
驱逐器获取到的股票价格:9.0
(stock_1,6.0)
驱逐器获取到的股票价格:10.0
(stock_1,10.0)

驱逐器会在每个窗口开始时检查所有输入的事件,并对那些满足特定条件的事件(在本例中,股票价格 <= 0)进行处理并移除。

stock_1, 1602031567000, 8 — 股票价格大于0,保留。
stock_1, 1602031568000, -4 — 股票价格小于0,驱逐。
stock_1, 1602031569000, 3 — 股票价格大于0,保留。
stock_1, 1602031570000, -8 — 股票价格小于0,驱逐。
stock_1, 1602031571000, 9 — 股票价格大于0,保留。
stock_1, 1602031572000, 10 — 股票价格大于0,保留。
驱逐器输出的处理结果:
窗口 1(时间区间:1602031567000 - 1602031570000,窗口大小 3秒):

该窗口内剩下的有效记录:stock_1, 1602031567000, 8 和 stock_1, 1602031569000, 3(-4 和 -8 被驱逐)。
计算平均价格:(8 + 3) / 2 = 5.5
输出: (stock_1, 8.0)(按窗口内第一个事件的 stockId 输出)
窗口 2(时间区间:1602031569000 - 1602031572000,窗口大小 3秒):

该窗口内剩下的有效记录:stock_1, 1602031569000, 3 和 stock_1, 1602031571000, 9(-8 被驱逐)。
计算平均价格:(3 + 9) / 2 = 6.0
输出: (stock_1, 6.0)(按窗口内第一个事件的 stockId 输出)
窗口 3(时间区间:1602031571000 - 1602031574000,窗口大小 3秒):

该窗口内剩下的有效记录:stock_1, 1602031571000, 9 和 stock_1, 1602031572000, 10。
计算平均价格:(9 + 10) / 2 = 9.5
输出: (stock_1, 10.0)(按窗口内第一个事件的 stockId 输出)

输出后的结果是:

驱逐器获取到的股票价格:8.0
驱逐器获取到的股票价格:-4.0
股票价格小于0,删除该记录
(stock_1,8.0)
驱逐器获取到的股票价格:3.0
驱逐器获取到的股票价格:-8.0
股票价格小于0,删除该记录
驱逐器获取到的股票价格:9.0
(stock_1,6.0)
驱逐器获取到的股票价格:10.0
(stock_1,10.0)

总结

以上就是今天要讲的内容,触发器和驱逐器。下一小节应该讲水位线啦。

相关文章:

【Flink-scala】DataStream编程模型之窗口计算-触发器-驱逐器

DataStream API编程模型 1.【Flink-Scala】DataStream编程模型之数据源、数据转换、数据输出 2.【Flink-scala】DataStream编程模型之 窗口的划分-时间概念-窗口计算程序 文章目录 DataStream API编程模型前言1.触发器1.1 代码示例 2.驱逐器2.1 代码示例 总结 前言 本小节我想…...

信号灯集以及 P V 操作

一、信号灯集 1.1 信号灯集的概念 信号灯集是进程间同步的一种方式。 信号灯集创建后&#xff0c;在信号灯集内部会有很多个信号灯。 每个信号灯都可以理解为是一个信号量。 信号灯的编号是从0开始的。 比如A进程监视0号灯&#xff0c;B进程监视1号灯。 0号灯有资源&…...

在 Flutter app 中,通过视频 URL 下载视频到手机相册

在 Flutter app 中&#xff0c;通过视频 URL 下载视频到手机相册可以通过以下步骤实现&#xff1a; 1. 添加依赖 使用 dio 下载文件&#xff0c;结合 path_provider 获取临时存储路径&#xff0c;以及 gallery_saver 将文件保存到相册。 在 pubspec.yaml 中添加以下依赖&…...

Nature Methods | 人工智能在生物与医学研究中的应用

Nature Methods | 人工智能在生物与医学研究中的应用 生物研究中的深度学习 随着人工智能&#xff08;AI&#xff09;技术的迅速发展&#xff0c;尤其是深度学习和大规模预训练模型的出现&#xff0c;AI在生物学研究中的应用正在经历一场革命。从基因组学、单细胞组学到癌症生…...

Axure PR 9 随机函数 设计交互

​大家好&#xff0c;我是大明同学。 这期内容&#xff0c;我们将深入探讨Axure中随机函数的用法。 随机函数 创建随机函数所需的元件 1.打开一个新的 RP 文件并在画布上打开 Page 1。 2.在元件库中拖出一个矩形元件。 3.选中矩形元件&#xff0c;样式窗格中&#xff0c;将…...

【人工智能基础05】决策树模型

文章目录 一. 基础内容1. 决策树基本原理1.1. 定义1.2. 表示成条件概率 2. 决策树的训练算法2.1. 划分选择的算法信息增益&#xff08;ID3 算法&#xff09;信息增益比&#xff08;C4.5 算法&#xff09;基尼指数&#xff08;CART 算法&#xff09;举例说明&#xff1a;计算各个…...

【人工智能基础03】机器学习(练习题)

文章目录 课本习题监督学习的例子过拟合和欠拟合常见损失函数&#xff0c;判断一个损失函数的好坏无监督分类&#xff1a;kmeans无监督分类&#xff0c;Kmeans 三分类问题变换距离函数选择不同的起始点 重点回顾1. 监督学习、半监督学习和无监督学习的定义2. 判断学习场景3. 监…...

HarmonyOS(60)性能优化之状态管理最佳实践

状态管理最佳实践 1、避免在循环中访问状态变量1.1 反例1.2 正例 2、避免不必要的状态变量的使用3、建议使用临时变量替换状态变量3.1 反例3.2 正例 4、参考资料 1、避免在循环中访问状态变量 在应用开发中&#xff0c;应避免在循环逻辑中频繁读取状态变量&#xff0c;而是应该…...

数据库课程设计报告 超市会员管理系统

一、系统简介 1.1设计背景 受到科学技术的推动&#xff0c;全球计算机的软硬件技术迅速发展&#xff0c;以计算机为基础支撑的信息化如今已成为现代企业的一个重要标志与衡量企业综合实力的重要标准&#xff0c;并且正在悄无声息的影响与改变着国内外广泛的中小型企业的运营模…...

C++算法练习-day54——39.组合总和

题目来源&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 题目思路分析 题目&#xff1a;给定一个整数数组 candidates 和一个目标数 target&#xff0c;找出所有独特的组合&#xff0c;这些组合中的数字之和等于 target。每个数字在每个组合中只能使用一次。 思路&a…...

计算机毕业设计PySpark+Hadoop中国城市交通分析与预测 Python交通预测 Python交通可视化 客流量预测 交通大数据 机器学习 深度学习

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…...

Linux的文件系统

这里写目录标题 一.文件系统的基本组成索引节点目录项文件数据的存储扇区三个存储区域 二.虚拟文件系统文件系统分类进程文件表读写过程 三.文件的存储连续空间存放方式缺点 非连续空间存放方式链表方式隐式链表缺点显示链接 索引数据库缺陷索引的方式优点&#xff1a;多级索引…...

【Vue3】从零开始创建一个VUE项目

【Vue3】从零开始创建一个VUE项目 手动创建VUE项目附录 package.json文件报错处理: Failed to get response from https://registry.npmjs.org/vue-cli-version-marker 相关链接&#xff1a; 【VUE3】【Naive UI】&#xff1c;NCard&#xff1e; 标签 【VUE3】【Naive UI】&…...

9)语法分析:半倒装和全倒装

在英语中&#xff0c;倒装是一种特殊的句子结构&#xff0c;其中主语和谓语&#xff08;或助动词&#xff09;的位置被颠倒。倒装分为部分倒装和全倒装两种类型&#xff0c;它们的主要区别在于倒装的程度和使用的场合。 1. 部分倒装 (Partial Inversion) 部分倒装是指将助动词…...

Scala关于成绩的常规操作

score.txt中的数据&#xff1a; 姓名&#xff0c;语文&#xff0c;数学&#xff0c;英语 张伟&#xff0c;87&#xff0c;92&#xff0c;88 李娜&#xff0c;90&#xff0c;85&#xff0c;95 王强&#xff0c;78&#xff0c;90&#xff0c;82 赵敏&#xff0c;92&#xff0c;8…...

使用Java实现度分秒坐标转十进制度的实践

目录 前言 一、度分秒的使用场景 1、表示方法 2、两者的转换方法 3、区别及使用场景 二、Java代码转换的实现 1、确定计算值的符号 2、数值的清洗 3、度分秒转换 4、转换实例 三、总结 前言 在地理信息系统&#xff08;GIS&#xff09;、导航、测绘等领域&#xff0c…...

根据后台数据结构,构建搜索目录树

效果图&#xff1a; 数据源 const data [{"categoryidf": "761525000288210944","categoryids": "766314364226637824","menunamef": "经济运行","menunames": "经济运行总览","tempn…...

食品计算—FoodSAM: Any Food Segmentation

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…...

2411rust,1.83

原文 1.83.0稳定版 新的常能力 此版本包括几个说明在常环境中运行代码可干的活的大型扩展.这是指编译器在编译时必须计算的所有代码:常和静项的初值,数组长度,枚举判定值,常模板参数及可从(constfn)此类环境调用的函数. 引用静.当前,除了静项的初化器式外,禁止常环境引用静…...

tomcat加载三方包顺序

共享库 tomcat支持多个webapp共享一个三方库&#xff0c;而不需要每个webapp都引入该三方库 tomcat加载类顺序 bootstrap&#xff1a;加载jvm提供的类system&#xff1a;加载$CATALINA_HOME/bin下的bootstrap.jar,commons-daemon.jar,tomcat-juli.jar三个包//加载$CLASSPATH…...

计算机的错误计算(一百七十一)

摘要 探讨 MATLAB 中秦九韶&#xff08;Horner&#xff09;多项式的错误计算。 例1. 用秦九韶&#xff08;Horner&#xff09;算法计算&#xff08;一百零七&#xff09;例1中多项式 直接贴图吧&#xff1a; 这样&#xff0c;MATLAB 给出的仍然是错误结果&#xff0c;因为准…...

js对于json的序列化、反序列化有哪几种方法

在JavaScript中&#xff0c;对JSON&#xff08;JavaScript Object Notation&#xff09;进行序列化&#xff08;将对象转换为JSON字符串&#xff09;和反序列化&#xff08;将JSON字符串转换为对象&#xff09;是常见的操作。以下是一些常用的方法&#xff1a; 序列化&#xf…...

Linux——基础命令(2) 文件内容操作

目录 ​编辑 文件内容操作 1.Vim &#xff08;1&#xff09;移动光标 &#xff08;2&#xff09;复制 &#xff08;3&#xff09;剪切 &#xff08;4&#xff09;删除 &#xff08;5&#xff09;粘贴 &#xff08;6&#xff09;替换,撤销,查找 &#xff08;7&#xff…...

简单搭建qiankun的主应用和子应用并且用Docker进行服务器部署

在node18环境下&#xff0c;用react18创建qiankun主应用和两个子应用&#xff0c;react路由用V6版本&#xff0c;都在/main路由下访问子应用&#xff0c;用Dockerfile部署到腾讯云CentOS7.6服务器的8000端口进行访问&#xff0c;且在部署过程中进行nginx配置以进行合理的路由访…...

Python知识分享第十六天

“”" 故事7: 小明把煎饼果子技术传给徒弟的同时, 不想把独创配方传给他, 我们就要加私有. 问: 既然不想让子类用, 为什么要加私有? 答: 私有的目的不是不让子类用, 而是不让子类直接用, 而必须通过特定的 途径或者方式才能使用. 大白话: ATM机为啥要设计那么繁琐, 直接…...

管家婆财贸ERP BR045.大类存货库存数量明细表

最低适用版本&#xff1a; C系列 23.8 插件简要功能说明&#xff1a; 库存数量明细表支持按存货展示数据更多细节描述见下方详细文档 插件操作视频&#xff1a; 进销存类定制插件--大类存货库存数量明细表 插件详细功能文档&#xff1a; 应用中心增加菜单【大类存货库存数…...

Pytorch-GPU版本离线安装

最近在复现一项深度学习的工作&#xff0c;发现自己的pytorch是装的cpu版的(好像当时是直接加清华源&#xff0c;默认是cpu版本&#xff09;。从官网在线下载速度太慢&#xff0c;还时不时断开连接&#xff0c;我们可以配置conda的清华源去这个问题&#xff0c;但是考虑到是在用…...

k8s 1.28 二进制安装与部署

第一步 &#xff1a;配置Linux服务器 #借助梯子工具 192.168.196.100 1C8G kube-apiserver、kube-controller-manager、kube-scheduler、etcd、kubectl、haproxy、keepalived 192.168.196.101 1C8G kube-apiserver、kube-controller-manager、kube-scheduler、etcd、kubectl、…...

【C语言】扫雷游戏(一)

我们先设计一个简单的9*9棋盘并有10个雷的扫雷游戏。 1&#xff0c;可以用数组存放&#xff0c;如果有雷就用1表示&#xff0c;没雷就用0表示。 2&#xff0c;排查(2,5)这个坐标时&#xff0c;我们访问周围的⼀圈8个位置黄色统计周围雷的个数是1。排查(8,6)这个坐标时&#xf…...

二分法篇——于上下边界的扭转压缩间,窥见正解辉映之光(1)

前言 二分法&#xff0c;这一看似简单却又充满哲理的算法&#xff0c;犹如一道精巧的数学之门&#xff0c;带领我们在问题的迷雾中找到清晰的道路。它的名字虽简单&#xff0c;却深藏着智慧的光辉。在科学的浩瀚星空中&#xff0c;二分法如一颗璀璨的星辰&#xff0c;指引着我们…...

网站开发需求/什么是seo标题优化

[彻底解决 configparser 中文乱码问题,让你的 Python3 代码更加优雅] Python3 configparser 是一个非常重要的模块,它可以帮助我们读取和写入配置文件,很多项目都会用到这个模块。但是在使用过程中,我们可能会遇到中文乱码的问题,这给我们的编码工作带来了很大的困扰。 …...

做包子网站/搜索历史记录

ASP.NET笔试题是ASP.NET程序员面试必须经历的&#xff0c;一般会叫你填两个表 1个是你的详细信息表 1个是面试题答卷两个都要注意反正面是否都有内容不要遗漏&#xff0c;如果考你机试一般也有两种&#xff0c;就是程序连接数据库或一些基本的算法&#xff08;二分查找&#xf…...

淘宝上那些做网站seo的管用吗/武汉it培训机构排名前十

1.在MySQL中创建数据库 """创建mysql数据库""" import pymysql # 数据库连接引用类 from pymysql.connections import Connection # 游标操作类 from pymysql.cursors import Cursor# 通过pymysql的方法connect()方法声明一个MySQL连接对象conn。…...

私募基金网站开发流程/百度关键词推广帝搜软件

dplyr函数进行数据转换 筛选知识铺垫比较运算符逻辑运算符数据准备filter()函数筛选行select()函数筛选列arrange()函数排列行完整代码dplyr()函数是R语言数据分析必学的实用包之一。 本文现阶段先讲解dplyr()函数的几个常用于数据转换的函数&#xff1a;filter()函数、select(…...

使用word做网站/磁力狗bt

OGG12C配置环境配置&#xff1a;安装数据库Oracle12c安装源端OGG&#xff1a;oggs PORT:7809安装目标端OGG&#xff1a;oggt PORT:7909源端和目标端地址&#xff1a;127.0.0.1源端数据库&#xff1a;-----修改源数据库配置&#xff1a;SQL> sqlplus / as sysdba;SQL>a…...

做网站哪一家公司好/营销网站建设大概费用

在皕杰报表的函数中&#xff0c;数据集函数和单元格函数都有sum求和函数&#xff0c;但其用法是不同的。我们先看两个函数的说明&#xff1a; 一、数据集函数sum 函数说明&#xff1a;从数据集中&#xff0c;从满足条件的记录中&#xff0c;算出给定字段或表达式的总和 语法&a…...