Flink状态包括:算子状态和按键分区状态,简单理解就是记录任务的中间状态或者数值
基于 KeyedStream 上的状态。这个状态是跟特定的 key 绑定的,对 KeyedStream 流上的每一个 key,都对应一个 state。
按键分区状态分为:ValueState、ListState、ReducingState、MapState、AggregatingState
即类型为T的单值状态
package com.xx.state;
import com.xx.entity.WaterSensor;
import com.xx.functions.WaterSensorMapFunction;
import org.apache.flink.api.common.eventtime.WatermarkStrategy;
import org.apache.flink.api.common.state.ValueState;
import org.apache.flink.api.common.state.ValueStateDescriptor;
import org.apache.flink.api.common.typeinfo.Types;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.KeyedProcessFunction;
import org.apache.flink.util.Collector;
import java.time.Duration;
/**
* @author xiaxing
* @describe Flink状态管理
* 算子状态(Keyed State):状态是跟特定的 key 绑定的,对 KeyedStream 流上的每一个 key,都对应一个 state
* ValueState:即类型为T的单值状态
* ListState:即key上的状态值为一个列表
* MapState:状态值为一个 map
* ReducingState:这种状态通过用户传入的 reduceFunction,每次调用 add 方法添加值的时候,会调用 reduceFunction,最后合并到一个单一的状态值
* 按键分区状态(Operator State):与 Key 无关的 State,与 Operator 绑定的 state,整个 operator 只对应一个 state
* @since 2024/3/29 11:10
*/
public class KeyedValueStateDemo {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setParallelism(1);
SingleOutputStreamOperator<WaterSensor> sensorDS = env.socketTextStream("127.0.0.1", 7777)
.map(new WaterSensorMapFunction())
.assignTimestampsAndWatermarks(
WatermarkStrategy.<WaterSensor>forBoundedOutOfOrderness(Duration.ofSeconds(3))
.withTimestampAssigner((element, ts) -> element.getTs() * 1000L));
// 数值差超过10则告警
sensorDS.keyBy(WaterSensor::getId).process(new KeyedProcessFunction<String, WaterSensor, String>() {
ValueState<Integer> lastVcState;
@Override
public void open(Configuration parameters) throws Exception {
super.open(parameters);
lastVcState = getRuntimeContext()
.getState(new ValueStateDescriptor<>("lastVcState", Types.INT));
}
@Override
public void processElement(WaterSensor value, KeyedProcessFunction<String, WaterSensor, String>.Context ctx, Collector<String> out) throws Exception {
// 1.取出上一条数据的水位值
Integer lastVc = lastVcState.value() == null ? 0 : lastVcState.value();
// 2.就差值绝对值,判断是否超过10
int abs = Math.abs(value.getVc() - lastVc);
if (abs > 10) {
out.collect("id为:" + value.getId() + ",当前水位值:" + value.getVc() + ",上一条水位值:" + lastVc + ",相差超过10!!!");
}
// 3.保存自身水位值
lastVcState.update(value.getVc());
}
}).print();
env.execute();
}
}
即key上的状态值为一个列表
package com.xx.state;
import com.xx.entity.WaterSensor;
import com.xx.functions.WaterSensorMapFunction;
import org.apache.flink.api.common.eventtime.WatermarkStrategy;
import org.apache.flink.api.common.state.ListState;
import org.apache.flink.api.common.state.ListStateDescriptor;
import org.apache.flink.api.common.typeinfo.Types;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.KeyedProcessFunction;
import org.apache.flink.util.Collector;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
/**
* @author xiaxing
* @describe Flink状态管理
* 算子状态(Keyed State):状态是跟特定的 key 绑定的,对 KeyedStream 流上的每一个 key,都对应一个 state
* ValueState:即类型为T的单值状态
* ListState:即key上的状态值为一个列表
* MapState:状态值为一个 map
* ReducingState:这种状态通过用户传入的 reduceFunction,每次调用 add 方法添加值的时候,会调用 reduceFunction,最后合并到一个单一的状态值
* 按键分区状态(Operator State):与 Key 无关的 State,与 Operator 绑定的 state,整个 operator 只对应一个 state
* @since 2024/3/29 11:10
*/
public class KeyedListStateDemo {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setParallelism(1);
SingleOutputStreamOperator<WaterSensor> sensorDS = env.socketTextStream("127.0.0.1", 7777)
.map(new WaterSensorMapFunction())
.assignTimestampsAndWatermarks(
WatermarkStrategy.<WaterSensor>forBoundedOutOfOrderness(Duration.ofSeconds(3))
.withTimestampAssigner((element, ts) -> element.getTs() * 1000L));
// 取最大的三个数值
sensorDS.keyBy(WaterSensor::getId).process(new KeyedProcessFunction<String, WaterSensor, String>() {
ListState<Integer> listState;
@Override
public void open(Configuration parameters) throws Exception {
super.open(parameters);
listState = getRuntimeContext()
.getListState(new ListStateDescriptor<>("vcListState", Types.INT));
}
@Override
public void processElement(WaterSensor value, KeyedProcessFunction<String, WaterSensor, String>.Context ctx, Collector<String> out) throws Exception {
// 1.写数据
listState.add(value.getVc());
// 2.降序排序
List<Integer> result = new ArrayList<>();
for (Integer vc : listState.get()) {
result.add(vc);
}
result.sort((o1, o2) -> o2 - o1);
// 3.只保留最大的三个
if (result.size() > 3) {
result.remove(3);
}
out.collect("id为:" + value.getId() + ",最大的三个水位值:" + result);
// 4.更新数据
listState.update(result);
}
}).print();
env.execute();
}
}
状态值为一个map
package com.xx.state;
import com.xx.entity.WaterSensor;
import com.xx.functions.WaterSensorMapFunction;
import org.apache.flink.api.common.eventtime.WatermarkStrategy;
import org.apache.flink.api.common.state.MapState;
import org.apache.flink.api.common.state.MapStateDescriptor;
import org.apache.flink.api.common.typeinfo.Types;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.KeyedProcessFunction;
import org.apache.flink.util.Collector;
import java.time.Duration;
/**
* @author xiaxing
* @describe Flink状态管理
* 算子状态(Keyed State):状态是跟特定的 key 绑定的,对 KeyedStream 流上的每一个 key,都对应一个 state
* ValueState:即类型为T的单值状态
* ListState:即key上的状态值为一个列表
* MapState:状态值为一个 map
* ReducingState:这种状态通过用户传入的 reduceFunction,每次调用 add 方法添加值的时候,会调用 reduceFunction,最后合并到一个单一的状态值
* 按键分区状态(Operator State):与 Key 无关的 State,与 Operator 绑定的 state,整个 operator 只对应一个 state
* @since 2024/3/29 11:10
*/
public class KeyedMapStateDemo {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setParallelism(1);
SingleOutputStreamOperator<WaterSensor> sensorDS = env.socketTextStream("127.0.0.1", 7777)
.map(new WaterSensorMapFunction())
.assignTimestampsAndWatermarks(
WatermarkStrategy.<WaterSensor>forBoundedOutOfOrderness(Duration.ofSeconds(3))
.withTimestampAssigner((element, ts) -> element.getTs() * 1000L));
// 统计每个key出现的次数
sensorDS.keyBy(WaterSensor::getId).process(new KeyedProcessFunction<String, WaterSensor, String>() {
MapState<Integer, Integer> mapState;
@Override
public void open(Configuration parameters) throws Exception {
super.open(parameters);
mapState = getRuntimeContext()
.getMapState(new MapStateDescriptor<>("vcMapState", Types.INT, Types.INT));
}
@Override
public void processElement(WaterSensor value, KeyedProcessFunction<String, WaterSensor, String>.Context ctx, Collector<String> out) throws Exception {
Integer vc = value.getVc();
if (mapState.contains(vc)) {
Integer count = mapState.get(vc);
count ++;
mapState.put(vc, count);
} else {
mapState.put(vc, 1);
}
StringBuilder str = new StringBuilder();
str.append("id为:").append(value.getId());
for (Integer key : mapState.keys()) {
str.append(",key:").append(key).append(",value:").append(mapState.get(key));
}
out.collect(str.toString());
}
}).print();
env.execute();
}
}
这种状态通过用户传入的 reduceFunction,每次调用 add 方法添加值的时候,会调用 reduceFunction,最后合并到一个单一的状态值
package com.xx.state;
import com.xx.entity.WaterSensor;
import com.xx.functions.WaterSensorMapFunction;
import org.apache.flink.api.common.eventtime.WatermarkStrategy;
import org.apache.flink.api.common.functions.ReduceFunction;
import org.apache.flink.api.common.state.ReducingState;
import org.apache.flink.api.common.state.ReducingStateDescriptor;
import org.apache.flink.api.common.typeinfo.Types;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.KeyedProcessFunction;
import org.apache.flink.util.Collector;
import java.time.Duration;
/**
* @author xiaxing
* @describe Flink状态管理
* 算子状态(Keyed State):状态是跟特定的 key 绑定的,对 KeyedStream 流上的每一个 key,都对应一个 state
* ValueState:即类型为T的单值状态
* ListState:即key上的状态值为一个列表
* MapState:状态值为一个 map
* ReducingState:这种状态通过用户传入的 reduceFunction,每次调用 add 方法添加值的时候,会调用 reduceFunction,最后合并到一个单一的状态值
* 按键分区状态(Operator State):与 Key 无关的 State,与 Operator 绑定的 state,整个 operator 只对应一个 state
* @since 2024/3/29 11:10
*/
public class KeyedReducingStateDemo {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setParallelism(1);
SingleOutputStreamOperator<WaterSensor> sensorDS = env.socketTextStream("127.0.0.1", 7777)
.map(new WaterSensorMapFunction())
.assignTimestampsAndWatermarks(
WatermarkStrategy.<WaterSensor>forBoundedOutOfOrderness(Duration.ofSeconds(3))
.withTimestampAssigner((element, ts) -> element.getTs() * 1000L));
// 累加
sensorDS.keyBy(WaterSensor::getId).process(new KeyedProcessFunction<String, WaterSensor, String>() {
ReducingState<Integer> reducingState;
@Override
public void open(Configuration parameters) throws Exception {
super.open(parameters);
reducingState = getRuntimeContext()
.getReducingState(new ReducingStateDescriptor<>("vcReduceState", (ReduceFunction<Integer>) Integer::sum, Types.INT));
}
@Override
public void processElement(WaterSensor value, KeyedProcessFunction<String, WaterSensor, String>.Context ctx, Collector<String> out) throws Exception {
reducingState.add(value.getVc());
out.collect("id为:" + value.getId() + ",水位线总和:" + reducingState.get());
}
}).print();
env.execute();
}
}
package com.xx.state;
import com.xx.entity.WaterSensor;
import com.xx.functions.WaterSensorMapFunction;
import org.apache.flink.api.common.eventtime.WatermarkStrategy;
import org.apache.flink.api.common.functions.AggregateFunction;
import org.apache.flink.api.common.state.AggregatingState;
import org.apache.flink.api.common.state.AggregatingStateDescriptor;
import org.apache.flink.api.common.typeinfo.Types;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.KeyedProcessFunction;
import org.apache.flink.util.Collector;
import java.time.Duration;
/**
* @author xiaxing
* @describe Flink状态管理
* 算子状态(Keyed State):状态是跟特定的 key 绑定的,对 KeyedStream 流上的每一个 key,都对应一个 state
* ValueState:即类型为T的单值状态
* ListState:即key上的状态值为一个列表
* MapState:状态值为一个 map
* ReducingState:这种状态通过用户传入的 reduceFunction,每次调用 add 方法添加值的时候,会调用 reduceFunction,最后合并到一个单一的状态值
* 按键分区状态(Operator State):与 Key 无关的 State,与 Operator 绑定的 state,整个 operator 只对应一个 state
* 状态生存时间(ttl)
* @since 2024/3/29 11:10
*/
public class KeyedAggregatingStateDemo {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setParallelism(1);
SingleOutputStreamOperator<WaterSensor> sensorDS = env.socketTextStream("127.0.0.1", 7777)
.map(new WaterSensorMapFunction())
.assignTimestampsAndWatermarks(
WatermarkStrategy.<WaterSensor>forBoundedOutOfOrderness(Duration.ofSeconds(3))
.withTimestampAssigner((element, ts) -> element.getTs() * 1000L));
// 累加
sensorDS.keyBy(WaterSensor::getId).process(new KeyedProcessFunction<String, WaterSensor, String>() {
AggregatingState<Integer, Double> AggregatingState;
@Override
public void open(Configuration parameters) throws Exception {
super.open(parameters);
AggregatingState = getRuntimeContext()
.getAggregatingState(new AggregatingStateDescriptor<>("aggregatingState", new AggregateFunction<Integer, Tuple2<Integer, Integer>, Double>() {
@Override
public Tuple2<Integer, Integer> createAccumulator() {
return Tuple2.of(0, 0);
}
@Override
public Tuple2<Integer, Integer> add(Integer value, Tuple2<Integer, Integer> accumulator) {
return Tuple2.of(accumulator.f0 + value, accumulator.f1 + 1);
}
@Override
public Double getResult(Tuple2<Integer, Integer> accumulator) {
return accumulator.f0 * 1D / accumulator.f1;
}
@Override
public Tuple2<Integer, Integer> merge(Tuple2<Integer, Integer> a, Tuple2<Integer, Integer> b) {
return null;
}
}, Types.TUPLE(Types.INT, Types.INT)));
}
@Override
public void processElement(WaterSensor value, KeyedProcessFunction<String, WaterSensor, String>.Context ctx, Collector<String> out) throws Exception {
AggregatingState.add(value.getVc());
out.collect("id为:" + value.getId() + ",平均水位值:" + AggregatingState.get());
}
}).print();
env.execute();
}
}
避免状态数据大量积累浪费资源
package com.xx.state;
import com.xx.entity.WaterSensor;
import com.xx.functions.WaterSensorMapFunction;
import org.apache.flink.api.common.eventtime.WatermarkStrategy;
import org.apache.flink.api.common.state.StateTtlConfig;
import org.apache.flink.api.common.state.ValueState;
import org.apache.flink.api.common.state.ValueStateDescriptor;
import org.apache.flink.api.common.time.Time;
import org.apache.flink.api.common.typeinfo.Types;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.KeyedProcessFunction;
import org.apache.flink.util.Collector;
import java.time.Duration;
/**
* @author xiaxing
* @describe Flink状态管理
* 算子状态(Keyed State):状态是跟特定的 key 绑定的,对 KeyedStream 流上的每一个 key,都对应一个 state
* ValueState:即类型为T的单值状态
* ListState:即key上的状态值为一个列表
* MapState:状态值为一个 map
* ReducingState:这种状态通过用户传入的 reduceFunction,每次调用 add 方法添加值的时候,会调用 reduceFunction,最后合并到一个单一的状态值
* 按键分区状态(Operator State):与 Key 无关的 State,与 Operator 绑定的 state,整个 operator 只对应一个 state
* @since 2024/3/29 11:10
*/
public class KeyedValueTtlStateDemo {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setParallelism(1);
SingleOutputStreamOperator<WaterSensor> sensorDS = env.socketTextStream("127.0.0.1", 7777)
.map(new WaterSensorMapFunction())
.assignTimestampsAndWatermarks(
WatermarkStrategy.<WaterSensor>forBoundedOutOfOrderness(Duration.ofSeconds(3))
.withTimestampAssigner((element, ts) -> element.getTs() * 1000L));
// 数值差超过10则告警
sensorDS.keyBy(WaterSensor::getId).process(new KeyedProcessFunction<String, WaterSensor, String>() {
ValueState<Integer> lastVcState;
@Override
public void open(Configuration parameters) throws Exception {
super.open(parameters);
// 创建ttl config
StateTtlConfig ttlConfig = StateTtlConfig
// 过期时间:5s
.newBuilder(Time.seconds(5))
// 状态更新和写入会刷新过期时间
.setUpdateType(StateTtlConfig.UpdateType.OnCreateAndWrite)
// 不返回过期的状态值
.setStateVisibility(StateTtlConfig.StateVisibility.NeverReturnExpired)
.build();
// 状态描述其启用ttl
ValueStateDescriptor<Integer> valueState = new ValueStateDescriptor<>("lastVcState", Types.INT);
valueState.enableTimeToLive(ttlConfig);
this.lastVcState = getRuntimeContext().getState(valueState);
}
@Override
public void processElement(WaterSensor value, KeyedProcessFunction<String, WaterSensor, String>.Context ctx, Collector<String> out) throws Exception {
Integer lastVc = lastVcState.value();
out.collect("id为:" + value.getId() + ",状态值:" + lastVc);
lastVcState.update(value.getVc());
}
}).print();
env.execute();
}
}
与 Key 无关的 State,与 Operator 绑定的 state,整个 operator 只对应一个 state,常用于Source和Sink等与外部系统链接的算子上,实际使用不多。
比如Flink中的Kafka Connector,它会在每个 connector 实例中,保存该实例中消费 topic 的所有(partition, offset)映射
算子状态包括:ListState、Broadcast State
package com.xx.state;
import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.api.common.state.ListState;
import org.apache.flink.api.common.state.ListStateDescriptor;
import org.apache.flink.api.common.typeinfo.Types;
import org.apache.flink.runtime.state.FunctionInitializationContext;
import org.apache.flink.runtime.state.FunctionSnapshotContext;
import org.apache.flink.streaming.api.checkpoint.CheckpointedFunction;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
/**
* @author xiaxing
* @describe 在map算子中计算数据个数
* @since 2024/3/29 15:34
*/
public class OperatorListStateDemo {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setParallelism(1);
env.socketTextStream("127.0.0.1", 7777)
.map(new MyCountMapFunction()).print();
env.execute();
}
public static class MyCountMapFunction implements MapFunction<String, Long>, CheckpointedFunction {
private Long count = 0L;
private ListState<Long> state;
@Override
public Long map(String value) throws Exception {
return count ++;
}
/**
* 将本地变量拷贝到算子状态中
*/
@Override
public void snapshotState(FunctionSnapshotContext context) throws Exception {
System.out.println("snapshotState...");
// 清空算子状态
state.clear();
// 将本地变量添加到状态算子中
state.add(count);
}
/**
* 初始化本地变量,从状态中,把数据添加到本地变量,每个子任务调用一次
*/
@Override
public void initializeState(FunctionInitializationContext context) throws Exception {
System.out.println("initializeState...");
// 从上下文初始化算子状态
state = context
.getOperatorStateStore()
.getListState(new ListStateDescriptor<>("state", Types.LONG));
// 从算子状态中将数据拷贝到本地变量
if (context.isRestored()) {
for (Long aLong : state.get()) {
count += aLong;
}
}
}
}
}
Broadcast State 是 Flink 1.5 引入的新特性。在开发过程中,如果遇到需要下发/广播配置、规则等低吞吐事件流到下游所有 task 时,就可以使用 Broadcast State 特性。下游的 task 接收这些配置、规则并保存为 BroadcastState, 将这些配置应用到另一个数据流的计算中 。
package com.xx.state;
import com.xx.entity.WaterSensor;
import com.xx.functions.WaterSensorMapFunction;
import org.apache.flink.api.common.state.BroadcastState;
import org.apache.flink.api.common.state.MapStateDescriptor;
import org.apache.flink.api.common.state.ReadOnlyBroadcastState;
import org.apache.flink.api.common.typeinfo.Types;
import org.apache.flink.streaming.api.datastream.BroadcastConnectedStream;
import org.apache.flink.streaming.api.datastream.BroadcastStream;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.co.BroadcastProcessFunction;
import org.apache.flink.util.Collector;
/**
* @author xiaxing
* @describe
* @since 2024/3/29 15:34
*/
public class OperatorBroadcastStateDemo {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setParallelism(1);
// 数据流
SingleOutputStreamOperator<WaterSensor> sensorDS = env.socketTextStream("127.0.0.1", 7777)
.map(new WaterSensorMapFunction());
// 配置流(用于广播配置)
DataStreamSource<String> configSource = env.socketTextStream("127.0.0.1", 8888);
// 将配置流广播
MapStateDescriptor<String, String> broadcastMapState = new MapStateDescriptor<>("broadcast-state", Types.STRING, Types.STRING);
BroadcastStream<String> broadcast = configSource.broadcast(broadcastMapState);
// 将数据流和广播后的配置链接
BroadcastConnectedStream<WaterSensor, String> connect = sensorDS.connect(broadcast);
connect.process(new BroadcastProcessFunction<WaterSensor, String, String>() {
/**
* 数据流处理方法
*/
@Override
public void processElement(WaterSensor value, BroadcastProcessFunction<WaterSensor, String, String>.ReadOnlyContext ctx, Collector<String> out) throws Exception {
// 通过上下文获取广播状态
ReadOnlyBroadcastState<String, String> broadcastState = ctx.getBroadcastState(broadcastMapState);
String config = broadcastState.get("config") == null ? "0" : broadcastState.get("config");
if (Integer.parseInt(config) < value.getVc()) {
out.collect("水位超过指定的预置:" + config + ",当前水位:" + value.getVc());
}
}
/**
* 广播后的配置流处理方法
*/
@Override
public void processBroadcastElement(String value, BroadcastProcessFunction<WaterSensor, String, String>.Context ctx, Collector<String> out) throws Exception {
// 通过上下文获取广播状态
BroadcastState<String, String> broadcastState = ctx.getBroadcastState(broadcastMapState);
broadcastState.put("config", value);
}
}).print();
env.execute();
}
}
文章浏览阅读82次。1.开始 在网站上传图片过程,经常用到缩略图功能。这里我自己写了一个图片处理的Image类,能生成缩略图,并且可以添加水印图。2.如何生成缩略图 生成缩略图,关键的是如何计算缩放比率。 这里,我根据图片等比缩放,宽高的几种常见变化,得出一个算缩放比率算法是,使用新图(即缩略图)的宽高,分别除以原图的宽高,看哪个值大,就取它作为缩放比率:...
文章浏览阅读2.7k次。在室友Xcode继承一些framework时,爆出了如下错误:dyld: Library not loaded: @rpath/libswiftCore.dylib Referenced from: /private/var/containers/Bundle/Application/1761A6FE-9D6B-45F7-9F9F-922C94BF54A3/demo.app/Framewor..._library not loaded: @rpath/libswiftcore.dylib
文章浏览阅读356次。光标控制命令h或^h向左移一个字符j或^j或^n向下移一行k或^p向上移一行l或空格向右移一个字符G移到文件的最后一行nG移到文件的第n行w..._gvim itab
文章浏览阅读1k次,点赞12次,收藏10次。按 name 卸载缓存状态下的 节点,name 可选类型为 String 或 RegExp,注意,仅卸载命中 的第一层内容,不会卸载 中嵌套的、未命中的。按 name 刷新缓存状态下的 节点,name 可选类型为 String 或 RegExp,注意,仅刷新命中 的第一层内容,不会刷新 中嵌套的、未命中的。按 name 卸载缓存状态下的 节点,name 可选类型为 String 或 RegExp,将卸载命中 的所有内容,包括 中嵌套的所有。true: 卸载时缓存。获取所有缓存中的节点。_umi-plugin-keep-alive
文章浏览阅读3k次,点赞2次,收藏25次。用了几天的memory compiler,搞清楚了它的使用流程。因为这个软件是不开源的,而且手册又很长,没有快速阅读指南,所以就花了挺多时间学习手册细节,想把其中比较主要的流程记录下来,供大家学习参考。它是一个用来综合一些IP核的软件,它里面各种各样的memory compiler,可以根据自己的选择选中一个,设置好参数之后就能生成想要的参数的memory。 因为每个memory compiler可能工艺不一样,端口数不一样,所以里面有手册告诉你这些细节的。(手册很多,每个手册几百页上下)1、首先就是要安装_memory compiler
文章浏览阅读5.6k次,点赞5次,收藏16次。前言什么是csv文件呢?百度百科上说 CSV是逗号分隔值文件格式,也有说是电子表格的,既然是电子表格,那么就可以用Excel打开,那为什么要在Android中来读取这个.csv格式的文件呢?因为现在主流数据格式是采用的JSON,但是另一种就是.csv格式的数据,这种数据通常由数据库直接提供,进行读取。下面来看看简单的使用吧正文首先还是先来创建一个项目,名为ReadCSV准备.csv格式的文件,点击和风APILocationList下载ZIP,保存到本地,然后解压,这个时候在你的项目文件中新建_android 读取csv
文章浏览阅读1.1k次。BIOS 是计算机历史上的一个重要组成部分。这个术语最早是在 20 世纪 70 年代作为 Gary Kildall 开发的 CP/M(微型计算机控制程序)操作系统的一部分使用的。但 BIOS 至今仍在使用。然而,成功的技术现在越来越多地用于现代计算机。Legacy BIOS 和 UEFI BIOSBIOS 的含义是什么?该术语是 Basic Input/Output System(基本输入/输出系统)的首字母缩写,它描述的是作为非易失性存储器储存在计算机主板上的固件。_legacy bios
文章浏览阅读2k次。GitLab Runner是一个开源项目,用于运行您的作业并将结果发送回GitLab。它与GitLab CI结合使用,GitLab CI是GitLab随附的用于协调作业的开源持续集成服务。。_gitlab-runner 16.1.2
文章浏览阅读449次,点赞7次,收藏7次。Redis、Memcached等常见的缓存数据库,以及它们各自的特点和优势,使得开发人员可以根据应用场景选择最适合的解决方案。通过合理地配置和使用缓存数据库,可以有效地改善应用程序的性能,降低数据库负载,为用户提供更流畅的体验。缓存数据库允许应用程序在需要数据时,首先从缓存中查询数据,如果数据存在,则可以避免直接访问主数据库,从而显著提高数据访问速度。主数据库通常面临大量读写请求,而缓存数据库可以分担部分读请求,减轻主数据库的负载,提高其稳定性和可靠性。缓存数据库可以作为主数据库的备份,以防止数据丢失。
文章浏览阅读3.3w次,点赞38次,收藏158次。前端开发是创建Web页面或app等前端界面呈现给用户的过程,通过HTML,CSS及JavaScript以及衍生出来的各种技术、框架、解决方案,来实现互联网产品的用户界面交互[1]。它从网页制作演变而来,名称上有很明显的时代特征。在互联网的演化进程中,网页制作是Web1.0时代的产物,,用户使用网站的行为也以浏览为主。随着互联网技术的发展和HTML5、CSS3的应用,现代网页更加美观,交互效果显著,功能更加强大。[2]..._vscode安装包
Linux下使用java -jar命令运行jar包,可通过ctrl + c或关闭窗口停止程序。可以使用pid文件记录jar包的运行进程,方便终止。通过编写启停脚本,可以方便地终止jar包的运行。
文章浏览阅读1.4w次,点赞8次,收藏40次。1. 名词 名词可以分为专有名词(Proper Nouns)和普通名词 (Common Nouns),专有名词是某个(些)人,地方,机构等专有的名称,如Beijing,China等。普通名词是一类人或东西或是一个抽象概念的名词,如: book,sadness等。普通名词又可分为下面四类: 1)个体名词(Individual Nouns):表示某类人或东西中的个体,如:gun。 2)集体..._英语基础语法