流式计算分为无状态和有状态两种情况。
1)无状态的计算观察每个独立事件,并根据最后一个事件输出结果。例如,流处理应用程序从传感器接收温度读
数,并在温度超过 90 度时发出警告。
2)有状态的计算则会基于多个事件输出结果。
以下是一些例子。
所有类型的窗口。例如,计算过去一小时的平均温度,就是有状态的计算。
所有用于复杂事件处理的状态机。例如,若在一分钟内收到两个相差 20 度以上的温度读数,则发出警告,这
是有状态的计算。
流与流之间的所有关联操作,以及流与静态表或动态表之间的关联操作,都是有状态的计算。
下图展示了无状态流处理和有状态流处理的主要区别。无状态流处理分别接收每条数据记录(图中的黑条),然
后根据最新输入的数据生成输出数据(白条)。
有状态流处理会维护状态(根据每条输入记录进行更新),并基于最新输入的记录和当前的状态值生成输出记录
(灰条)。
上图中输入数据由黑条表示。无状态流处理每次只转换一条输入记录,并且仅根据最新的输入记录输出结果
(白条)。有状态流处理维护所有已处理记录的状态值,并根据每条新输入的记录更新状态,因此输出记录(灰条)反
映的是综合考虑多个事件之后的结果。
尽管无状态的计算很重要,但是流处理对有状态的计算更感兴趣。事实上,正确地实现有状态的计算比实现
无状态的计算难得多。旧的流处理系统并不支持有状态的计算,而新一代的流处理系统则将状态及其正确性
视为重中之重。
Flink 内置的很多算子,数据源 source,数据存储 sink 都是有状态的,流中的数据都是 buffer records,
会保存一定的元素或者元数据。例如: ProcessWindowFunction 会缓存输入流的数据,ProcessFunction 会保
存设置的定时器信息等等。
在 Flink 中,状态始终与特定算子相关联。总的来说,有两种类型的状态:
算子状态(operator state)
键控状态(keyed state)
算子状态的作用范围限定为算子任务。这意味着由同一并行任务所处理的所有数据都可以访问到相同的状
态,状态对于同一任务而言是共享的。
算子状态不能由相同或不同算子的另一个任务访问。
Flink 为算子状态提供三种基本数据结构:
列表状态(List state)
将状态表示为一组数据的列表。
联合列表状态(Union list state)
也将状态表示为数据的列表。它与常规列表状态的区别在于,在发生故障时,或者从保存点(savepoint)启
动应用程序时如何恢复。
广播状态(Broadcast state)
如果一个算子有多项任务,而它的每项任务状态又都相同,那么这种特殊情况最适合应用广播状态。
键控状态是根据输入数据流中定义的键(key)来维护和访问的。Flink 为每个键值维护一个状态实例,并将
具有相同键的所有数据,都分区到同一个算子任务中,这个任务会维护和处理这个 key 对应的状态。当任务处理
一条数据时,它会自动将状态的访问范围限定为当前数据的 key。因此,具有相同 key 的所有数据都会访问相同的
状态。
Keyed State 很类似于一个分布式的 key-value map 数据结构,只能用于 KeyedStream(keyBy 算子处理
之后)。
Flink 的 Keyed State 支持以下数据类型:
ValueState<T>保存单个的值,值的类型为 T。
get 操作: ValueState.value()
set 操作: ValueState.update(T value)
ListState<T>保存一个列表,列表里的元素的数据类型为 T。基本操作如下:
ListState.add(T value)
ListState.addAll(List<T> values)
ListState.get()返回 Iterable<T>
ListState.update(List<T> values)
MapState<K, V>保存 Key-Value 对。
MapState.get(UK key)
MapState.put(UK key, UV value)
MapState.contains(UK key)
MapState.remove(UK key)
ReducingState<T>
AggregatingState<I, O>
State.clear()是清空操作。
我们可以利用 Keyed State,实现这样一个需求:
检测传感器的温度值,如果连续的两个温度差值超过 10 度,就输出报警。
DataStream<Tuple3<String, Double, Double>> warningStream = dataStream .keyBy("id") .flatMap(new TempIncreaseWarning(10.0));
这里需要实现一个自定义的 RichFlatMapFuction,具体实现如下:
public static class TempIncreaseWarning extends RichFlatMapFunction<SensorReading, Tuple3<String, Double, Double>>{ private Double threshold; TempIncreaseWarning(Double threshold) { this.threshold = threshold; } private ValueState<Double> lastTempState; @Override public void open(Configuration parameters) throws Exception { lastTempState = getRuntimeContext().getState(new ValueStateDescriptor<Double>("last-temp", Double.class, Double.MIN_VALUE)); } @Override public void flatMap(SensorReading value, Collector<Tuple3<String, Double, Double>> out) throws Exception { Double lastTemp = lastTempState.value(); lastTempState.update(value.getTemperature()); if( lastTemp != Double.MIN_VALUE ) {// 跟最新的温度值计算差值,如果大于阈值,那么输出报警 Double diff = Math.abs(value.getTemperature() - lastTemp); if (diff > threshold) out.collect( new Tuple3<>(value.getId(), lastTemp, value.getTemperature()) ); } } }
➢ 通过 RuntimeContext 注册 StateDescriptor。
➢ StateDescriptor 以状态 state 的名字和存储的数据类型为参数。
➢ 在 open()方法中创建 state 变量。注意复习之前的 RichFunction 相关知识。
当在分布式系统中引入状态时,自然也引入了一致性问题。一致性实际上是"正确性级别"的另一种说法,也就
是说在成功处理故障并恢复之后得到的结果,与没有发生任何故障时得到的结果相比,前者到底有多正确?举例来
说,假设要对最近一小时登录的用户计数。在系统经历故障之后,计数结果是多少?如果有偏差,是有漏掉的计数
还是重复计数?
在flink中对有状态的流处理做了以下特点说明:
1)有状态的流处理,内部每个[算子]任务都可以有自己的状态。
2)对于流处理器内部来说,所谓的状态一致性,其实就是我们所说的计算结果要保证准确。
3)一条数据不应该丢失,也不应该重复计算。
4) 在遇到故障时可以恢复状态,恢复以后的重新计算,结果应该也是完全正确的。
如图:数据重做后,仍然要保持状态的一致性
在流处理中,一致性可以分为 3 个级别:
at-most-once (最多一次)
当任务故障时,最简单的做法是什么都不干,既不恢复丢失的状态,也不重播丢失的数据。 这其实是没有正
确性保障的委婉说法——故障发生之后,计数结果可能丢失。
at-least-once (至少一次)
在大多数的真实应用场景,我们希望不丢失事件。这种类型的保障称为 at-least-once,意思是所有的事件都
得到了处理,而一些事件还可能被处理多次。 这表示计数结果可能大于正确值,但绝不会小于正确值。也就是
说,计数程序在发生故障后可能多算,但是绝不会少算。
exactly-once (精确一次)
恰好处理一次是最严格的保证,也是最难实现的。恰好处理一次语义不仅仅意味着没有事件丢失,还意味着
针对每一个数据,内部状态仅仅更新一次。
曾经,at-least-once 非常流行。第一代流处理器(如 Storm 和 Samza)刚问世时只保证 at-least-once,原因有二:
保证 exactly-once 的系统实现起来更复杂。这在基础架构层(决定什么代表正确,以及 exactly-once 的范围是什么)和实现层都很有挑战性。
流处理系统的早期用户愿意接受框架的局限性,并在应用层想办法弥补(例如使应用程序具有幂等性,或者用批量计算层再做一遍计算)。
最先保证 exactly-once 的系统(Storm Trident 和 Spark Streaming)在性能和表现力这两个方面付出了很
大的代价。为了保证 exactly-once,这些系统无法单独地对每条记录运用应用逻辑,而是同时处理多条(一批)记
录,保证对每一批的处理要么全部成功,要么全部失败。这就导致在得到结果前,必须等待一批记录处理结束。因
此,用户经常不得不使用两个流处理框架(一个用来保证 exactly-once,另一个用来对每个元素做低延迟处理),
结果使基础设施更加复杂。
曾经,用户不得不在保证 exactly-once 与获得低延迟和效率之间权衡利弊。Flink 避免了这种权衡。 Flink 的
一个重大价值在于,它既保证了 exactly-once,也具有低延迟和高吞吐的处理能力。
从根本上说,Flink 通过使自身满足所有需求来避免权衡,它是业界的一次意义重大的技术飞跃。尽管这在外
行看来很神奇,但是一旦了解,就会恍然大悟。
目前我们看到的一致性保证都是由流处理器实现的,也就是说都是在 Flink 流处理器内部保证的;而在真实应
用中,流处理应用除了流处理器以外还包含了数据源(例如 Kafka)和输出到持久化系统。
端到端的一致性保证,意味着结果的正确性贯穿了整个流处理应用的始终;每一个组件都保证了它自己的一
致性,整个端到端的一致性级别取决于所有组件中一致性最弱的组件。具体可以划分如下:
内部保证 —— 依赖 checkpoint
source 端 —— 需要外部源可重设数据的读取位置
sink 端 —— 需要保证从故障恢复时,数据不会重复写入外部系统
而对于 sink 端,又有两种具体的实现方式:幂等(Idempotent)写入和事务性(Transactional)写入。
幂等写入
所谓幂等操作,是说一个操作,可以重复执行很多次,但只导致一次结果更改, 也就是说,后面再重复执行
就不起作用了。
事务写入
需要构建事务来写入外部系统,构建的事务对应着 checkpoint,等到 checkpoint 真正完成的时候,才把所
有对应的结果写入 sink 系统中。
对于事务性写入,具体又有两种实现方式:预写日志(WAL)和两阶段提交(2PC)。DataStream API 提供
了 GenericWriteAheadSink 模板类和 TwoPhaseCommitSinkFunction 接口,可以方便地实现这两种方式的
事务性写入。
1) 预写日志(Write-Ahead-Log,WAL)
➢ 把结果数据先当成状态保存,然后在收到 checkpoint 完成的通知时, 一次性写入 sink 系统
➢ 简单易于实现,由于数据提前在状态后端中做了缓存,所以无论什么sink 系统,都能用这种方式一批搞定
➢ DataStream API 提供了一个模板类:GenericWriteAheadSink,来实现这种事务性 sink
2) 两阶段提交(Two-Phase-Commit,2PC)
➢ 对于每个 checkpoint,sink 任务会启动一个事务,并将接下来所有接收的数据添加到事务里
➢ 然后将这些数据写入外部 sink 系统,但不提交它们 —— 这时只是“预提交”
➢ 当它收到 checkpoint 完成的通知时,它才正式提交事务,实现结果的真正写入
2PC这种方式真正实现了exactly-once,它需要一个提供事务支持的外部 sink 系统。Flink 提供了
TwoPhaseCommitSinkFunction 接口。
1)外部 sink 系统必须提供事务支持,或者 sink 任务必须能够模拟外部系统上的事务
2)在 checkpoint 的间隔期间里,必须能够开启一个事务并接受数据写入
3)在收到 checkpoint 完成的通知之前,事务必须是“等待提交”的状态。 在故障恢复的情况下,这可能需要一些时间。如果这个时候sink系统关闭事务(例如超时了),那么未提交的数据就会丢失
4)sink 任务必须能够在进程失败后恢复事务
5)提交事务必须是幂等操作
不同 Source 和 Sink 的一致性保证可以用下表说明:
Flink 具体如何保证 exactly-once 呢? 它使用一种 种轻量级快照机制 被称为"检查点"(checkpoint)的特
性,在出现故障时将系统重置回正确状态。下面通过简单的类比来解释检查点的作用。
假设你和两位朋友正在数项链上有多少颗珠子,如下图所示。你捏住珠子,边数边拨,每拨过一颗珠子就给
总数加一。你的朋友也这样数他们手中的珠子。当你分神忘记数到哪里时,怎么办呢? 如果项链上有很多珠子,你
显然不想从头再数一遍,尤其是当三人的速度不一样却又试图合作的时候,更是如此(比如想记录前一分钟三人一
共数了多少颗珠子,回想一下一分钟滚动窗口)。
于是,你想了一个更好的办法:在项链上每隔一段就松松地系上一根有色皮筋, 将珠子分隔开; 当珠子被拨动
的时候,皮筋也可以被拨动; 然后,你安排一个助手,让他在你和朋友拨到皮筋时记录总数。用这种方法,当有人
数错时,就不必从头开 始数。相反,你向其他人发出错误警示,然后你们都从上一根皮筋处开始重数,助 手则会
告诉每个人重数时的起始数值,例如在粉色皮筋处的数值是多少。
Flink 检查点的作用就类似于皮筋标记。数珠子这个类比的关键点是: 对于指定的皮筋而言,珠子的相对位置
是确定的; 这让皮筋成为重新计数的参考点。总状态(珠子的总数)在每颗珠子被拨动之后更新一次,助手则会保存
与每根皮筋对应的检查点状态,如当遇到粉色皮筋时一共数了多少珠子,当遇到橙色皮筋时又是多少。 当问题出
现时,这种方法使得重新计数变得简单。
总结:
状态流应用的一致检查点,其实就是:
1)所有任务的状态,在某个时间点的一份拷贝(一份快照)。而这个时间点,应该是所有任务都恰好处理完一个相同的输入数据的时候。
有状态流应用的一致检查点,其实就是:所有任务的状态,在某个时间点的一份拷贝(一份快照)。而这个时间点,应该是所有任务都恰好处理完一个相同的输入数据的时候。
2)应用状态的一致检查点,是 Flink 故障恢复机制的核心
Flink 检查点的核心作用是确保状态正确,即使遇到程序中断,也要正确。记住这一基本点之后,我们用一个
例子来看检查点是如何运行的。Flink 为用户提供了用来定义状态的工具。
下图表示程序的初始状态: 输入流中的 6 条记录被检查点分割线(checkpoint barrier)隔开,所有的 map 算
子状态均为 0(计数还未开始),按key分组,数据采用累加方式进行最后输出。
所有 key 为 a 的记录将被顶层的 map 算子处理,所有 key 为 b的记录将被中间层的 map 算子处理,所有
key 为 c 的记录则将被底层的 map 算子处理。
上图是程序的初始状态。注意,a、b、c 三组的初始计数状态都是 0,即三个圆柱上的值。ckpt 表示检查点
分割线(checkpoint barriers)。每条记录在处理顺序上严格地遵守在检查点之前或之后的规定,例如
["b",2]在检查点之前被处理,["a",2]则在检查点之后被处理。
当该程序处理输入流中的 6 条记录时,涉及的操作遍布 3 个并行实例(节点、CPU内核等)。那么,检查点该如
何保证 exactly-once 呢?
检查点分割线和普通数据记录类似。它们由算子处理,但并不参与计算,而是会触发与检查点相关的行为。
当读取输入流的数据源(在本例中与 keyBy 算子内联) 遇到检查点屏障时,它将其在输入流中的位置保存到持久化
存储中。
如果输入流来自消息传输系统(Kafka),这个位置就是偏移量。Flink 的存储机制是插件化的,持久化存储可以是分布式文件系统,如 HDFS。下图展示了这个过程。
当 Flink 数据源(在本例中与 keyBy 算子内联)遇到检查点分界线(barrier)时, 它会将其在输入流中的位置
保存到持久化存储中。这让 Flink 可以根据该位置重启。
检查点像普通数据记录一样在算子之间流动。当 map 算子处理完前 3 条数据并收到检查点分界线时,它们会
将状态以异步的方式写入持久化存储,如下图所示。
位于检查点之前的所有记录(["b",2]、["b",3]和["c",1])被 map 算子处理之后的情 况。
此时,持久化存储已经备份了检查点分界线在输入流中的位置(备份操作发生在barrier 被输入算子处理的时
候)。map 算子接着开始处理检查点分界线,并触发将状 态异步备份到稳定存储中这个动作。
当 map 算子的状态备份和检查点分界线的位置备份被确认之后,该检查点操作就可以被标记为完成,如下图
所示。
我们在无须停止或者阻断计算的条件下,在一个逻辑时间点(对应检查点屏障在输入流中的位置)为计算状态拍
了快照。通过确保备份的状态和位置指向同一个逻辑时间点,后文将解释如何基于备份恢复计算,从 而保证
exactly-once。值得注意的是,当没有出现故障时,Flink 检查点的开销极小, 检查点操作的速度由持久化存储的
可用带宽决定。
回顾数珠子的例子: 除了因为数错而需要用到皮筋之外,皮筋会被很快地拨过。
检查点操作完成,状态和位置均已备份到稳定存储中。
输入流中的所有数据记录都已处理完成。值得注意的是,备份的状态值与实际的状态值是不同的。备份反
映的是检查点的状态。
如果检查点操作失败,Flink 可以丢弃该检查点并继续正常执行,因为之后的某一个检查点可能会成功。虽然
恢复时间可能更长,但是对于状态的保证依旧很有力。只有在一系列连续的检查点操作失败之后,Flink 才会抛出
错误,因为这通常预示着发生了严重且持久的错误。
现在来看看下图所示的情况: 检查点操作已经完成,但故障紧随其后。
在这种情况下,Flink 会重新拓扑(可能会获取新的执行资源),将输入流倒回到上一个检查点,然后恢复状态
值并从该处开始继续计算。在本例中,["a",2]、["a",2] 和["c",2]这几条记录将被重播。
下图展示了这一重新处理过程。从上一个检查点开始重新计算,可以保证在剩下的记录被处理之后,得到的
map 算子的状态值与没有发生故障时的状态值一致。
Flink 将输入流倒回到上一个检查点屏障的位置,同时恢复 map 算子的状态值。然后,Flink 从此处开始重新
处理。这样做保证了在记录被处理之后,map 算子的状态值与没有发生故障时的一致。
Flink 检查点算法的正式名称是异步分界线快照(asynchronous barrier snapshotting)。该算法大致基于
Chandy-Lamport 分布式快照算法。
检查点是 Flink 最有价值的创新之一,因为它使 Flink 可以保证 exactly-once, 并且不需要牺牲性能。
3.1示例中讲到异常处理步骤,如何进行重置,我们再来聊聊。
1)重启应用
遇到故障之后,第一步就是重启应用
2)状态重置
从 checkpoint 中读取状态,将状态重置
从检查点重新启动应用程序后,其内部状态与检查点完成时的状态完全相同
3)数据恢复
开始消费并处理检查点到发生故障之间的所有数据
这种检查点的保存和恢复机制可以为应用程序状态提供“精确一次” (exactly-once)的一致性,因为所有
算子都会保存检查点并恢复其所有状 态,这样一来所有的输入流就都会被重置到检查点完成时的位置
1)Flink 的检查点算法用到了一种称为分界线(barrier)的特殊数据形式,用来把一条流上数据按照不同的检查
点分开
2)分界线之前到来的数据导致的状态更改,都会被包含在当前分界线所属 的检查点中;而基于分界线之后的数据
导致的所有更改,就会被包含在 之后的检查点中
图例:
A)有两个输入流的应用程序,用并行的两个 Source 任务来读取
B)JobManager 会向每个 source 任务发送一条带有新检查点 ID 的消息,通过这 种方式来启动检查点
C)数据源将它们的状态写入检查点,并发出一个检查点 barrier
D)状态后端在状态存入检查点之后,会返回通知给 source 任务,source 任务就会向 JobManager 确认检查点完成
1)开始对齐
• 分界线对齐:barrier 向下游传递,sum 任务会等待所有输入分区的 barrier 到达
• 对于barrier已经到达的分区,继续到达的数据会被缓存
• 而barrier尚未到达的分区,数据会被正常处理
2)结束对齐
当收到所有输入分区的 barrier 时,任务就将其状态保存到状态后端的检查点中, 然后将 barrier 继续向下游转发
3)下游继续传递
向下游转发检查点 barrier 后,任务继续正常的数据处理
4)Sink确认
• Sink 任务向 JobManager 确认状态保存到 checkpoint 完毕
• 当所有任务都确认已成功将状态保存到检查点时,检查点就真正完成了
我们知道,端到端的状态一致性的实现,需要每一个组件都实现,对于 Flink + Kafka 的数据管道系统
(Kafka 进、Kafka 出)而言,各组件怎样保证 exactly-once 语义呢?
内部 —— 利用 checkpoint 机制,把状态存盘,发生故障的时候可以恢复, 保证内部的状态一致性
source —— kafka consumer 作为 source,可以将偏移量保存下来,如果后续任务出现了故障,恢复的时候
可以由连接器重置偏移量,重新消费数据, 保证一致性
sink —— kafka producer 作为 sink,采用两阶段提交 sink,需要实现一个TwoPhaseCommitSinkFunction
内部的 checkpoint 机制我们已经有了了解,那 source 和 sink 具体又是怎样运行的呢?接下来我们逐步做一
个分析。
我们知道 Flink 由 JobManager 协调各个 TaskManager 进行 checkpoint 存储, checkpoint 保存在
StateBackend 中,默认 StateBackend 是内存级的,也可以改为文件级的进行持久化保存。
具体的两阶段提交步骤总结如下:
第一条数据来了之后,开启一个 kafka 的事务(transaction),正常写入kafka 分区日志但标记为未提交,这
就是“预提交”
jobmanager 触发 checkpoint 操作,barrier 从 source 开始向下传递,遇到barrier 的算子将状态存入状态后
端,并通知 jobmanager
sink 连接器收到 barrier,保存当前状态,存入 checkpoint,通知 jobmanager,并开启下一阶段的事务,用
于提交下个检查点的数据
jobmanager 收到所有任务的通知,发出确认信息,表示 checkpoint 完成
sink 任务收到 jobmanager 的确认信息,正式提交这段时间的数据
外部 kafka 关闭事务,提交的数据可以正常消费了。
所以我们也可以看到,如果宕机需要通过 StateBackend 进行恢复,只能恢复所有确认提交的操作。
1)Flink 还提供了可以自定义的镜像保存功能,就是保存点(savepoints)
2)原则上,创建保存点使用的算法与检查点完全相同,因此保存点可以认为就是具有一些额外元数据的检查点
3)Flink不会自动创建保存点,因此用户(或者外部调度程序)必须明确地触发创建操作
4)保存点是一个强大的功能。除了故障恢复外,保存点可以用于:有计划 的手动备份,更新应用程序,版本迁移,暂停和重启应用,等等
MemoryStateBackend
内存级的状态后端,会将键控状态作为内存中的对象进行管理,将它们存储在 TaskManager 的 JVM 堆上;
而将 checkpoint 存储在 JobManager 的内存中。
FsStateBackend
将 checkpoint 存到远程的持久化文件系统(FileSystem)上。而对于本地状态,跟 MemoryStateBackend
一样,也会存在 TaskManager 的 JVM 堆上。
RocksDBStateBackend
将所有状态序列化后,存入本地的 RocksDB 中存储。
注意:RocksDB 的支持并不直接包含在 flink 中,需要引入依赖:
<dependency> <groupId>org.apache.flink</groupId> <artifactId>flink-statebackend-rocksdb_2.12</artifactId> <version>1.10.1</version> </dependency>
设置状态后端为 FsStateBackend,并配置检查点和重启策略:
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); env.setParallelism(1); // 1. 状态后端配置 env.setStateBackend(new FsStateBackend("")); // 2. 检查点配置 env.enableCheckpointing(1000); env.getCheckpointConfig().setCheckpointingMode(CheckpointingMode.EXACTLY_ONCE); env.getCheckpointConfig().setCheckpointTimeout(60000); env.getCheckpointConfig().setMinPauseBetweenCheckpoints(500); env.getCheckpointConfig().setMaxConcurrentCheckpoints(1); env.getCheckpointConfig().setPreferCheckpointForRecovery(false); env.getCheckpointConfig().setTolerableCheckpointFailureNumber(0); // 3. 重启策略配置 // 固定延迟重启(隔一段时间尝试重启一次) env.setRestartStrategy(RestartStrategies.fixedDelayRestart( 3, // 尝试重启次数 100000 // 尝试重启的时间间隔,也可 org.apache.flink.api.common.time.Time ));
文章浏览阅读1.6k次。安装配置gi、安装数据库软件、dbca建库见下:http://blog.csdn.net/kadwf123/article/details/784299611、检查集群节点及状态:[root@rac2 ~]# olsnodes -srac1 Activerac2 Activerac3 Activerac4 Active[root@rac2 ~]_12c查看crs状态
文章浏览阅读1.3w次,点赞45次,收藏99次。我个人用的是anaconda3的一个python集成环境,自带jupyter notebook,但在我打开jupyter notebook界面后,却找不到对应的虚拟环境,原来是jupyter notebook只是通用于下载anaconda时自带的环境,其他环境要想使用必须手动下载一些库:1.首先进入到自己创建的虚拟环境(pytorch是虚拟环境的名字)activate pytorch2.在该环境下下载这个库conda install ipykernelconda install nb__jupyter没有pytorch环境
文章浏览阅读5.2k次,点赞19次,收藏28次。选择scoop纯属意外,也是无奈,因为电脑用户被锁了管理员权限,所有exe安装程序都无法安装,只可以用绿色软件,最后被我发现scoop,省去了到处下载XXX绿色版的烦恼,当然scoop里需要管理员权限的软件也跟我无缘了(譬如everything)。推荐添加dorado这个bucket镜像,里面很多中文软件,但是部分国外的软件下载地址在github,可能无法下载。以上两个是官方bucket的国内镜像,所有软件建议优先从这里下载。上面可以看到很多bucket以及软件数。如果官网登陆不了可以试一下以下方式。_scoop-cn
文章浏览阅读4.5k次,点赞2次,收藏3次。首先要有一个color-picker组件 <el-color-picker v-model="headcolor"></el-color-picker>在data里面data() { return {headcolor: ’ #278add ’ //这里可以选择一个默认的颜色} }然后在你想要改变颜色的地方用v-bind绑定就好了,例如:这里的:sty..._vue el-color-picker
文章浏览阅读640次。基于芯片日益增长的问题,所以内核开发者们引入了新的方法,就是在内核中只保留函数,而数据则不包含,由用户(应用程序员)自己把数据按照规定的格式编写,并放在约定的地方,为了不占用过多的内存,还要求数据以根精简的方式编写。boot启动时,传参给内核,告诉内核设备树文件和kernel的位置,内核启动时根据地址去找到设备树文件,再利用专用的编译器去反编译dtb文件,将dtb还原成数据结构,以供驱动的函数去调用。firmware是三星的一个固件的设备信息,因为找不到固件,所以内核启动不成功。_exynos 4412 刷机
文章浏览阅读2w次,点赞24次,收藏42次。Linux系统配置jdkLinux学习教程,Linux入门教程(超详细)_linux配置jdk
文章浏览阅读3.3k次,点赞5次,收藏19次。xlabel('\delta');ylabel('AUC');具体符号的对照表参照下图:_matlab微米怎么输入
文章浏览阅读119次。顺序读写指的是按照文件中数据的顺序进行读取或写入。对于文本文件,可以使用fgets、fputs、fscanf、fprintf等函数进行顺序读写。在C语言中,对文件的操作通常涉及文件的打开、读写以及关闭。文件的打开使用fopen函数,而关闭则使用fclose函数。在C语言中,可以使用fread和fwrite函数进行二进制读写。 Biaoge 于2024-03-09 23:51发布 阅读量:7 ️文章类型:【 C语言程序设计 】在C语言中,用于打开文件的函数是____,用于关闭文件的函数是____。
文章浏览阅读3.4k次,点赞2次,收藏13次。跟随鼠标移动的粒子以grid(SOP)为partical(SOP)的资源模板,调整后连接【Geo组合+point spirit(MAT)】,在连接【feedback组合】适当调整。影响粒子动态的节点【metaball(SOP)+force(SOP)】添加mouse in(CHOP)鼠标位置到metaball的坐标,实现鼠标影响。..._touchdesigner怎么让一个模型跟着鼠标移动
文章浏览阅读178次。项目运行环境配置:Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。项目技术:Springboot + mybatis + Maven +mysql5.7或8.0+html+css+js等等组成,B/S模式 + Maven管理等等。环境需要1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。_基于java技术的停车场管理系统实现与设计
文章浏览阅读3.5k次。前言对于MediaPlayer播放器的源码分析内容相对来说比较多,会从Java-&amp;gt;Jni-&amp;gt;C/C++慢慢分析,后面会慢慢更新。另外,博客只作为自己学习记录的一种方式,对于其他的不过多的评论。MediaPlayerDemopublic class MainActivity extends AppCompatActivity implements SurfaceHolder.Cal..._android多媒体播放源码分析 时序图
文章浏览阅读2.4k次,点赞41次,收藏13次。java 数据结构与算法 ——快速排序法_快速排序法