Flink-序列化
一、概述
几乎每个Flink作业都必须在其运算符之间交换数据,由于这些记录不仅可以发送到同一JVM中的另一个实例,还可以发送到单独的进程,因此需要先将记录序列化为字节。类似地,Flink的堆外状态后端基于本地嵌入式RocksDB实例,该实例以本机C++代码实现,因此也需要在每次状态访问时转换为字节。如果执行不正确,仅有线和状态序列化就很容易消耗作业的大量性能,因此,每当您查看Flink作业的分析器输出时,您很可能会在使用CPU周期的顶部看到序列化。
因此,序列化对我们的Flink作业至关重要
本质上,Flink试图推断有关作业数据类型的信息以进行连接和状态序列化,并能够通过引用单个字段名称来使用分组、连接和聚合操作,例如stream. keyBy("ruleId")或dataSet.connect(另一个).where("name").equalTo("个性化名称")。它还允许优化序列化格式以及减少不必要的去序列化(主要是在某些批处理操作以及SQL/表API中)。
二、序列化器选择
Flink的开箱即用序列化大致有以下几种:
- Flink为基本类型(Java原语及其装箱形式)、数组、复合类型(元组、Scala案例类、行)和一些辅助类型(Option, Either, Lists, Maps…)提供了特殊的序列化程序
- POJO:一个公共的、独立的类,具有公共的无参数构造函数和类层次结构中的所有非静态、非瞬态字段,要么是公共的,要么是公共的getter-和setter-method;
- 泛型类型:不被识别为POJO然后通过Kryo序列化的用户定义数据类型。
- 自定义序列化程序:可以为用户定义的数据类型注册自定义序列化程序。这包括编写自己的序列化程序或通过Kryo集成其他序列化系统,如Google Pro buf或Apache Thrift。
PojoSerializer
如果我们的数据类型没有被专门的序列化程序覆盖,但遵循POJO规则,Flink将使用PojoSerializer序列化,PojoSerializer使用Java反射来访问对象的字段。它快速、通用、特定于Flink,并支持开箱即用的状态模式演变。如果复合数据类型不能序列化为POJO,我们可以在集群日志中找到以下消息(或类似消息):
15:45:51,460 INFO org.apache.flink.api.java.typeutils.TypeExtractor - Class … cannot be used as a POJO type because not all fields are valid POJO fields, and must be processed as GenericType. Please read the Flink documentation on “Data Types & Serialization” for details of the effect on performance.
这意味着,PojoSerializer将不会被使用,而是Flink将回退到Kryo进行序列化。当然还会有一些情况可能导致Kryo意外回退的情况。
Tuple Data Types
Flink带有一组预定义的元组类型,它们都具有固定的长度,并包含一组可能不同类型的强类型字段。有Tuple0、Tuple1<T0>、…、Tuple25<T0、T1、…、T24>的实现,它们可以作为易于使用的包装器,为我们需要在计算之间传递的每个对象组合节省POJO的创建。除了Tuple0之外,这些都是使用TupleSerializer和相应字段的序列化器序列化和反序列化的。由于元组类完全在Flink的控制之下,因此可以通过直接访问适当的字段来执行这两个操作而无需反射。
在使用元组而不是POJO时,这当然是一个(性能)优势。然而,元组在代码中并不那么灵活,描述性肯定也较差。
Row Data Types
行类型主要由Flink的Table和SQLAPI使用。Row将任意数量的对象组合在一起,类似于上面的元组。这些字段不是强类型的,可能都是不同的类型。由于缺少字段类型,Flink的类型提取不能自动提取类型信息,Row的用户需要手动告诉Flink该行的字段类型。然后RowSerializer将利用这些类型进行高效的序列化。
行类型信息可以通过两种方式提供:
1、让源或运算符实现ResultTypeQueryable<Row>
public static class RowSource implements SourceFunction<Row>, ResultTypeQueryable<Row> {// ...@Overridepublic TypeInformation<Row> getProducedType() {return Types.ROW(Types.INT, Types.STRING, Types.OBJECT_ARRAY(Types.STRING));}
}
在构建作业图时使用SingleOutputStreamOperator#returns()提供类型
DataStream<Row> sourceStream =env.addSource(new RowSource()).returns(Types.ROW(Types.INT, Types.STRING, Types.OBJECT_ARRAY(Types.STRING)));
如果您未能提供“行”的类型信息,Flink会根据上述规则识别“行”不是有效的POJO类型,并回退到Kryo序列化,这样性能就会下降。
flink 自带的TupleSerializer性能最高,其中一部分原因来源于不需要使用反射来访问 Tuple 中的字段。PojoSerializer 比 TupleSerializer性能差一些,但是比 kryo 的序列化方式性能要高几倍。
Avro
Flink通过将org. apache.flink:flink-avro依赖项添加到作业中来提供对Apache Avro序列化框架(当前使用版本1.8.2)的内置支持。然后,Flink的AvroSerializer可以使用Avro的Specific、Generic和 Reflect数据序列化,并利用Avro的性能和灵活性,特别是在类随时间变化时演变模式方面。
Avro Specific
通过检查给定类型的类型层次结构是否包含SpecificRecordBase类,将自动检测Avro特定记录。可以指定具体的Avro类型,或者——如果我们想更通用并在运算符中允许不同的类型——在我们用户函数中、在ResultTypeQueryable#getProducedType()中或在SingleOutputStreamOperator中使用SpecificRecordBase类型(或子类型)。由于特定记录使用生成的Java代码,因此它们是强类型的,并允许通过已知的getter和setter直接访问字段。
⚠:如果您将Flink类型指定为“SpecificRecord”而不是“SpecificRecordBase”,Flink不会将其视为Avro类型。相反,它将使用Kryo对任何可能相当慢的对象进行解/序列化
Avro Generic
不幸的是,Avro的GenericRecord类型不能自动使用,因为它们需要用户指定模式(手动或从某些模式注册表中检索)。使用该模式,我们可以通过以下任一选项提供正确的类型信息,就像上面的行类型一样:
- implement
ResultTypeQueryable<GenericRecord>
:
public static class AvroGenericSource implements SourceFunction<GenericRecord>, ResultTypeQueryable<GenericRecord> {private final GenericRecordAvroTypeInfo producedType;public AvroGenericSource(Schema schema) {this.producedType = new GenericRecordAvroTypeInfo(schema);}@Overridepublic TypeInformation<GenericRecord> getProducedType() {return producedType;}
}
- 在构建作业图时使用
SingleOutputStreamOperator#returns()
DataStream<GenericRecord> sourceStream =env.addSource(new AvroGenericSource()).returns(new GenericRecordAvroTypeInfo(schema));
如果没有这种类型信息,Flink将回退到Kryo进行序列化,这将一遍又一遍地将模式序列化到每条记录中。因此,序列化的形式将更大,创建成本更高。
注意:由于Avro的Schema类不可序列化,因此不能按原样发送。我们可以通过将其转换为字符串并在需要时解析它来解决这个问题。如果在初始化时只这样做一次,那么直接发送实际上没有区别。
Avro Reflect
使用Avro的第三种方法是将Flink的PojoSerializer(根据上述规则用于POJO)交换为Avro的基于反射的序列化器。这可以通过调用以下代码实现:
env.getConfig().enableForceAvro();
Kryo
任何不属于上述类别或被Flink提供的特殊序列化程序覆盖的类或对象都将被解/序列化,并回退到Kryo(当前版本2.24.0),这是Java中一个强大的通用序列化框架。Flink将此类类型称为泛型类型,我们在调试代码时可能会偶然发现GenericTypeInfo。如果使用Kryo序列化,请确保向kryo注册使用的类型:
env.getConfig().registerKryoType(MyCustomType.class);
注册类型会将它们添加内部map(class->tag)中,这样在序列化过程中,Kryo就不必将完全限定的类名作为前缀添加到序列化形式中。相反,Kryo使用这些(整数)标签来识别底层类并减少序列化开销。
注意:Flink将在其检查点和保存点中存储来自类型注册的Kryo serializer mappings,并在作业(重新)启动时保留它们。
禁用Kryo
如果需要,您可以通过调用禁用Kryo回退,即序列化泛型类型的能力
env.getConfig().disableGenericTypes();
这对于找出这些回退的应用位置并用更好的序列化程序替换它们非常有用。如果我们的作业有任何具有此配置的泛型类型,它将失败
Apache Thrift(通过Kryo)
除了上面的变体之外,Flink还允许我们向Kryo注册其他类型的序列化框架。从留档(com.twitter:chill-thrift
和 org.apache.thrift:libthrift
)添加适当的依赖项后,可以像下面这样使用Apache Thrift:
env.getConfig().addDefaultKryoSerializer(MyCustomType.class, TBaseSerializer.class);
这仅在未禁用泛型类型并且MyCustomType是Thrift生成的数据类型时才有效。如果数据类型不是由Thrift生成的,Flink将在运行时失败。
Protobuf(通过Kryo)
在类似于Apache Thrift的方式中,添加正确的依赖项(com.twitter:chill-protobuf
和 com.google.protobuf:protobuf-java
)后,Google Protobuf可以注册为自定义序列化程序:
env.getConfig().registerTypeWithKryoSerializer(MyCustomType.class, ProtobufSerializer.class);
只要泛型类型没有被禁用,这就可以工作(这将永久禁用Kryo)。如果MyCustomType不是Protobuf生成的类,Flink作业将在运行时失败。
三、状态模式演变
在仔细研究上述每个序列化程序的性能之前,我们想强调的是,性能并不是实际Flink作业中的一切。例如,用于存储状态的类型应该能够在作业的整个生命周期内发展其模式(添加/删除/更改字段),而不会丢失以前的状态。这就是Flink所说的状态模式演变。目前,从Flink 1.10开始,只有两个序列化程序支持开箱即用的模式演变:POJO和Avro。
对于其他任何事情,如果我们想更改状态模式,必须实现自己的自定义序列化程序或使用状态处理器API为新代码修改状态。
四、性能对比
有这么多的序列化选项,要做出正确的选择其实并不容易。我们已经看到了上面概述的每一个的一些技术优势和劣势。由于序列化程序是我们Flink作业的核心,并且通常也作用在热路径上(每个记录调用),所以让我们在https://github.com/dataArtisans/flink-benchmarks的Flink基准项目的帮助下实际更深入地了解它们的性能。这个项目在Flink之上添加了一些微基准(有些比其他更低级)来跟踪性能回归和改进。Flink用于监控序列化堆栈性能的持续基准在SerializationFrameworkMiniBenchmarks.java中实现。
不过,这只是所有可用序列化基准测试的一个子集,我们将在SerializationFrameworkAllBenchmarks.java中找到完整的集合。所有这些都使用可能涵盖平均用例的小型POJO的相同定义。本质上(没有构造函数、getter和setter),这些是它用于评估性能的数据类型:
public class MyPojo {public int id;private String name;private String[] operationNames;private MyOperation[] operations;private int otherId1;private int otherId2;private int otherId3;private Object someObject;
}
public class MyOperation {int id;protected String name;
}
这被适当地映射到tuples、行、Avro specific、Thrift和Protobuf 表示,并通过并行度=4的简单Flink作业发送,其中数据类型在网络通信期间使用,如下所示:
env.setParallelism(4);
env.addSource(new PojoSource(RECORDS_PER_INVOCATION, 10)).rebalance().addSink(new DiscardingSink<>());
在通过SerializationFrameworkAllBenchmarks.java中定义的jmh微基准测试运行后,得到了官方给出的Flink 1.10以下性能结果(以每毫秒的操作数为单位):
从图中我们可以得到以下信息:
-
从POJO到Kryo的默认回退将性能降低了75%。与使用POJO相比,向Kryo注册类型显着提高了其性能,仅减少了64%的操作。
-
Avro GenericRecord和SpecificRecord的序列化速度大致相同。
-
Avro Reflect序列化甚至比Kryo默认值(-45%)还要慢。
-
Tuples 是最快的,紧随其后的是Rows。两者都利用基于直接访问的快速专用序列化代码,无需Java反射。
-
使用(嵌套)Tuples 而不是POJO可能会使工作速度提高42%(但灵活性较低!)。为PojoSerializer(FLINK-3599)生成代码实际上可能会缩小这一差距(或者至少更接近RowSerializer)。
-
如果不能使用POJO,请尝试使用为其生成特定代码的序列化框架之一来定义用到的数据类型:Protobuf 、Avro、Thrift(按性能顺序)。
注意与所有基准测试一样,请记住,这些数字只能提示Flink在特定场景中的序列化器性能。它们可能因您的数据类型而异,但粗略的分类可能是相同的。如果你不放心,可以使用你的数据类型验证结果。
五、结论
我们研究了Flink如何对不同类型的数据类型执行序列化,并详细说明了技术上的优缺点。对于Flink状态下使用的数据类型,推荐使用POJO或Avro类型,目前,它们是唯一支持开箱即用状态演进的类型,并允许在有状态应用程序随着时间的推移而开发。POJO通常在反序列化方面更快,而Avro可能支持更灵活的模式演进,并且可以更好地与外部系统集成。但是请注意,我们可以对外部组件和内部组件甚至状态和网络通信使用不同的序列化程序
最快的反序列化是通过Flink的内部元组和行序列化器实现的,这些元组和行序列化器可以直接访问这些类型的字段,而无需通过反射。与元组相比,吞吐量降低了大约30%,Protobuf 和POJO类型本身的性能不会太差,并且更加灵活和可维护。Avro(specific and generic)记录以及Thrift数据类型分别进一步降低了20%和30%的性能。所以我们要想方设法避免Kryo,因为这会进一步降低约50%甚至更多的吞吐量!
那么如何避免Kryo的常见陷阱和障碍呢?如何充分利用PojoSerializer等序列化技术的调整呢?敬请关注,我们一起跟着官网壮大自己。
-------------------------------------------------------------------------------------------------------------------------------
大多数高校硕博生毕业要求需要参加学术会议,发表EI或者SCI检索的学术论文会议论文:
可访问艾思科蓝官网,浏览即将召开的学术会议列表。会议如下:
第八届大数据与应用统计国际学术研讨会(ISBDAS 2025)
https://ais.cn/u/fEzmy2
第二届生成式人工智能与信息安全国际学术会议(GAIIS 2025)
https://ais.cn/u/uAbENn
第四届电子技术与人工智能国际学术会议(ETAI 2025)
https://ais.cn/u/vqM7Nj
第四届网络安全、人工智能与数字经济国际学术会议(CSAIDE 2025)
https://ais.cn/u/ZrERn2
相关文章:
Flink-序列化
一、概述 几乎每个Flink作业都必须在其运算符之间交换数据,由于这些记录不仅可以发送到同一JVM中的另一个实例,还可以发送到单独的进程,因此需要先将记录序列化为字节。类似地,Flink的堆外状态后端基于本地嵌入式RocksDB实例&…...
1064 - You have an error in your SQL syntax;
在创建数据库表建立外键是遇到了如下报错 1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near position(position_id) ) at line 8 数据库表sql如下: --职位表 CR…...
团结引擎 Shader Graph:解锁图形创作新高度
Shader Graph 始终致力于为开发者提供直观且高效的着色器构建工具,持续推动图形渲染创作的创新与便捷。在团结引擎1.4.0中,Shader Graph 迎来了重大更新,新增多项强大功能并优化操作体验,助力开发者更轻松地实现高质量的渲染效果与…...
Spring Boot 配置 Mybatis 读写分离
JPA 的读写分离配置不能应用在 Mybatis 上, 所以 Mybatis 要单独处理 为了不影响原有代码, 使用了增加拦截器的方式, 在拦截器里根据 SQL 的 CRUD 来路由到不同的数据源 需要单独增加Mybatis的配置 Configuration public class MyBatisConfig {Beanpublic SqlSessionFactory…...
Redis 数据类型 List 列表
列表类型是⽤来存储多个有序的字符串,如下图所⽰,a、b、c、d、e 五个元素从左到右组成了⼀个有序的列表,列表中的每个字符串称为元素(element),⼀个列表最多可以存储 2^32 - 1个元素。在 Redis 中ÿ…...
Hello Robot 推出Stretch 3移动操作机器人,赋能研究与商业应用
Hello Robot公司近日发布了其新一代开源移动操作机器人Stretch 3,这是一款高度灵活的机器人平台,专为机器人研究、教育实验和商业自动化设计。Stretch 3 结合了先进的移动机器人技术、灵巧操作能力和开源软件生态系统,为用户提供了一个功能强…...
有滚动条的时候,设置盒子的位置
<div class"AIBox mt-24" id"AIBox"><div v-for"(v, i) in AIs" :key"i" :class"v.role assistant ? mb-24 : "><div :class"v.role user ? fc-ac42f3 fw-600 font-16 : ">{{ v.content }}…...
律所录音证据归集工具:基于PyQt6与多线程的自动化音频管理解决方案
在律所日常工作中,音频证据的整理与归集是一个高频且复杂的任务。面对大量的案件录音文件,如何实现快速且准确的分类与存档,成为了律所提高效率、降低出错率的关键。本文将通过技术角度解析一款名为律所录音证据归集工具的项目,详…...
LogicFlow自定义节点:矩形、HTML(vue3)
效果: LogicFlow 内部是基于MVVM模式进行开发的,分别使用preact和mobx来处理 view 和 model,所以当我们自定义节点的时候,需要为这个节点定义view和model。 参考官方文档:节点 | LogicFlow 1、自定义矩形节点 custo…...
软件工程教育的革命:AI辅助学习与实践
软件工程教育正面临着巨大的挑战。传统的教学模式往往以理论讲解为主,实践机会不足,导致学生难以将理论知识转化为实际技能。此外,繁琐的代码编写和项目搭建过程也常常耗费学生大量时间和精力,影响学习效率。为了解决这些问题&…...
Office hour 1
涉及Python环境配置、深度学习框架安装、常用数据处理和分析库、以及Python IDE的选择等内容。 1. Anaconda 安装与配置 • Anaconda Individual Edition:Anaconda 是一个开源平台,旨在简化数据科学的工作流程,提供了 Python 和超过 150 个科…...
【魔法阵——广义Dijkstra,DP】
题目 代码 #include <bits/stdc.h> using namespace std; const int N 1010; const int inf 0x3f3f3f3f; int g[N][N], d[N][N]; bool st[N][N]; int n, k, m; struct Node {int v, c, i;bool operator < (const Node &y) const{return v > y.v;} }; priori…...
使用epoll与sqlite3进行注册登录
将 epoll 服务器 客户端拿来用 客户端:写一个界面,里面有注册登录 服务器:处理注册和登录逻辑,注册的话将注册的账号密码写入数据库,登录的话查询数据库中是否存在账号,并验证密码是否正确 额外功能&…...
vue3-01-初识vue3相对于vue2的提升与比较,使用vue-cli创建项目,使用vite构建工具创建项目
1.相对于vue2的提升 2.创建vue3项目-使用vue-cli创建 2.1 cmd查看版本号 vue-V 2.2进入创建项目 切换D盘 D: 指定自定义创建的项目 cd 文件名 创建项目 vue create 项目名称 成功创建项目 运行项目 3.使用vite(构建工具)创建前端项目 3.1创建项目 3.1.1 npm init vite-ap…...
持久性HTTPVS.非持久性HTTP
1. HTTP协议基础 HTTP(HyperText Transfer Protocol)是Web通信的核心协议,定义了客户端(浏览器)与服务器之间传输数据的规则。 在HTTP/1.0及之前的版本中,默认使用非持久性连接,而HTTP/1.1及更…...
Node.js怎么调用到打包的python文件呢
在 Node.js 中调用打包后的 Python 可执行文件(如 PyInstaller 生成的 .exe 或二进制文件),可以通过以下步骤实现: 一、Python 打包准备 假设已有打包好的 Python 文件 your_script.exe(以 Windows 为例)&…...
C++,STL容器,map/multimap:映射/多重映射深入解析
文章目录 一、容器概览核心特性对比二、底层实现原理三、核心操作详解1. 容器初始化2. 元素插入操作3. 元素访问与查找4. 元素删除操作四、实战应用场景1. 高频数据统计2. 事件调度系统五、性能优化策略1. 键类型选择2. 内存管理优化六、注意事项与陷阱1. 迭代器失效问题2. 自定…...
【IDEA】2017版本的使用
目录 一、常识 二、安装 1. 下载IDEA2017.exe 2. 安装教程 三、基本配置 1. 自动更新关掉 2. 整合JDK环境 3. 隐藏.idea文件夹和.iml等文件 四、创建Java工程 1. 新建项目 2. 创建包结构,创建类,编写main主函数,在控制台输出内容。…...
理解Unity中的ExecuteInEditMode与ExecuteAlways
深入理解Unity中的[ExecuteInEditMode]与[ExecuteAlways] 一、引言 在开发Unity项目时,有时我们需要在编辑器模式下执行某些脚本逻辑,以实现即时反馈或特定的编辑功能。Unity提供了两种方式来满足这种需求:[ExecuteInEditMode]和[ExecuteAlways]。本文将详细介绍这两种特性…...
MybatisPlus常用增删改查
记录下MybatisPlus的简单的增删改查 接口概述 Service和Mapper区别 Mapper简化了单表的sql操作步骤(CRUD),而Serivce则是对Mapper的功能增强。 Service虽然加入了数据库的操作,但还是以业务功能为主,而更加复杂的SQL…...
【Java】多线程和高并发编程(三):锁(下)深入ReentrantReadWriteLock
文章目录 4、深入ReentrantReadWriteLock4.1 为什么要出现读写锁4.2 读写锁的实现原理4.3 写锁分析4.3.1 写锁加锁流程概述4.3.2 写锁加锁源码分析4.3.3 写锁释放锁流程概述&释放锁源码 4.4 读锁分析4.4.1 读锁加锁流程概述4.4.1.1 基础读锁流程4.4.1.2 读锁重入流程4.4.1.…...
JDK8 stream API用法汇总
目录 1.集合处理数据的弊端 2. Steam流式思想概述 3. Stream流的获取方式 3.1 根据Collection获取 3.1 通过Stream的of方法 4.Stream常用方法介绍 4.1 forEach 4.2 count 4.3 filter 4.4 limit 4.5 skip 4.6 map 4.7 sorted 4.8 distinct 4.9 match 4.10 find …...
帕累托改革(Pareto improvement)
帕累托改革(Pareto improvement)是经济学中的一个概念,指的是一种资源配置的改进方式,其中至少有一个人的处境变得更好,同时没有任何人的处境变得更差。这个概念来源于意大利经济学家维尔弗雷多帕累托,他发…...
Unity做2D小游戏2------创建地形和背景
我是跟着这个up主做的:【unity/2d/超基础】教你做一款2d横版游戏 打开Unity Hub后,点击项目--新项目,进入下面的界面,可以根据想要做的项目选择对应的模型,我现在要做2D小游戏,所以选择第一个2D核心模板。…...
欧拉筛详解(代码,证明过程以及时间复杂度分析)
1.欧拉筛的作用 欧拉筛:可以在线性的时间复杂度内,从1~n之间的素数的集合,并且在操作过程中可以记录素数数组,为以后判断是否是素数而加快效率 和大部分的筛法一样,通过将质数的倍数标记为合数来不断筛选质数的一种方…...
索引为什么是B+树结构,MySQL有哪些引擎,有什么区别?
目录 为什么索引使用 B+ 树结构? 1. 适合磁盘存储 2. 高效的查询性能 3. 适合大数据量 4. 与 B 树的区别 MySQL 的存储引擎及区别 1. InnoDB 2. MyISAM 3. Memory 4. Archive 5. CSV 6. Blackhole 存储引擎的选择建议 总结 为什么索引使用 B+ 树结构? B+ 树是…...
MongoDB进阶篇-索引
文章目录 1. 索引概述 2. 索引的类型 2.1 单字段索引 2.2 复合索引 2.3 其他索引 2.3.1 地理空间索引(Geospatial Index) 2.3.2 文本索引(Text Indexes) 2.3.3 哈希索引(Hashed Indexes) 3. 索引相关操作 3.1 查看索引 3.2 创建索引 3.3.1 创建单字段索引 3.3.2 创建复合…...
Unity WebGL包体压缩
最近在开发webgl,踩了很多坑,先来说下包体的问题。 开发完之后发现unity将文件都合并到一个文件了,一共有接近100m。 这对网页端的体验来说是可怕的,因为玩家必须要加载完所有的文件才能进入,这样体验特别差。 于是想…...
内容中台赋能人工智能技术提升业务创新能力
内容概要 在当今快速变化的市场环境中,企业需要不断寻求创新以保持竞争力。内容中台作为一种新型的内容管理架构,能够极大地提升企业在内容创建、管理和分发方面的效率。通过与人工智能技术的深度融合,企业能够将海量的数据和信息转化为有价…...
数据结构:队列
1.概念: 和栈相反,队列是一种先进先出的线性表它只允许在标的一段进行插入,而在另一端进行删除元素。这和我们日常生活中的排队是一致的,即最早入队的元素最早离开。队列中允许插入的一端叫做队尾,允许删除的一端的叫…...
第四期书生大模型实战营-第4关-L2G4000
简述多模态大模型的工作原理 多模态大模型是一种能够同时理解和生成多种类型数据(如文本、图像、音频、视频等)的人工智能模型。其核心工作原理可概括为以下几个关键步骤: 1. 多模态数据编码 模态对齐:将不同形式的数据…...
17vue3实战-----使用配置文件生成简易页面
17vue3实战-----使用配置文件生成简易页面 1.写在前面2.背景3.实现3.1界面效果3.2新建config配置文件3.3封装组件3.4使用组件 1.写在前面 后台管理系统的开发很简单。无论是用户模块、部门模块、角色模块还是其它模块,界面和业务逻辑都相对比较简单,我会省略这些模…...
ZZNUOJ(C/C++)基础练习1091——1100(详解版)⭐
目录 1091 : 童年生活二三事(多实例测试) C C 1092 : 素数表(函数专题) C C 1093 : 验证哥德巴赫猜想(函数专题) C C 1094 : 统计元音(函数专题) C C 1095 : 时间间隔(多…...
浏览器的缓存方式几种
浏览器的缓存方式主要分为以下几种: 1. 强制缓存(强缓存 / Memory Cache & Disk Cache) 通过 Expires 或 Cache-Control 头部控制。在缓存有效期内,浏览器直接使用缓存,不发起请求。 关键HTTP头: Ex…...
【前端】【面试】【经典一道题】vue中组件传值的几种方式
父子组件传值 1. 父传子:props 这是最常见的父组件向子组件传递数据的方式。父组件在使用子组件时,通过在子组件标签上绑定属性来传递数据,子组件通过 props 选项接收这些数据。 <!-- 父组件 --> <template><div><Ch…...
SwiftUI 中 .overlay 两种写法的区别及拓展
SwiftUI 中 .overlay 两种写法的区别及拓展 一、.overlay 简介功能语法 二、写法 1:.overlay(Circle().stroke(Color.blue, lineWidth: 2))代码示例解释优点适用场景 三、写法 2:.overlay { Circle().stroke(.white, lineWidth: 4) }代码示例解释优点适用…...
简述mysql 主从复制原理及其工作过程,配置一主两从并验证
原理: MySQL主从复制是基于事件的复制机制。主服务器负责处理所有的写操作和事务,并将这些更改(如INSERT、UPDATE和DELETE)以事件的形式记录到二进制日志(binlog)中。从服务器则通过读取主服务器的二进制日…...
python-leetcode 25.环形链表
题目: 给定一个链表的头节点head,判断链表中是否有环。 如果链表中有某个节点,可以通过连续跟踪next指针再次到达,则链表中存在环。为了表示给定链表中的环,评测系统内部使用整数pos来表示链表尾连接到链表中的位置(…...
游戏引擎学习第98天
仓库:https://gitee.com/mrxiao_com/2d_game_2 开始进行一点回顾 今天的目标是继续实现正常贴图的操作,尽管目前我们还没有足够的光照信息来使其完全有用。昨日完成了正常贴图相关的基础工作,接下来将集中精力实现正常贴图的基本操作,并准备…...
机器学习 - 进一步理解最大似然估计和高斯分布的关系
一、高斯分布得到的是一个概率吗? 高斯分布(也称为正态分布)描述的是随机变量在某范围内取值的概率分布情况。其概率密度函数(PDF)为: 其中,μ 是均值,σ 是标准差。 需要注意的是…...
物联网水质监测系统设计与实现/基于STM32的水产养殖云监控系统设计
背景 随着物联网技术的飞速发展,各行各业都在逐步实现智能化管理,水质监测系统作为环境监测中的一个重要环节,近年来备受关注。如何高效、精准地监测水质,尤其是在远程无法到达的地方,成为了一个迫切需要解决的问题。…...
【学习笔记】计算机网络(三)
第3章 数据链路层 文章目录 第3章 数据链路层3.1数据链路层的几个共同问题3.1.1 数据链路和帧3.1.2 三个基本功能3.1.3 其他功能 - 滑动窗口机制 3.2 点对点协议PPP(Point-to-Point Protocol)3.2.1 PPP 协议的特点3.2.2 PPP协议的帧格式3.2.3 PPP 协议的工作状态 3.3 使用广播信…...
Android 系统面试问题
一.android gki和非gki的区别 Android GKI(Generic Kernel Image)和非GKI内核的主要区别在于内核设计和模块化程度,具体如下: 1. 内核设计 GKI:采用通用内核设计,与设备硬件分离,核心功能统一…...
大疆无人机二次开发调试准备
以下机场和遥控器模式只能同时支持一种,因为无人机只能同时对频一种设备,如果同时对频了两种,以最后对频设备为准 机场模式 保证机场的网口闪烁,网络正常在mqtt中给dock建立用户,配置新建的MQTT账号和密码。组织ID任…...
【嵌入式Linux应用开发基础】文件I/O基础编程
目录 一、文件I/O简介 二、文件描述符 2.1. 唯一性 2.2. 抽象性 2.3. 有限性 三、文件操作函数 四、标准文件I/O函数 五、文件执行权限 5.1. 权限类型 5.2. 权限分配对象 5.3. 权限表示方法 5.4. 权限设置命令 5.5. 权限设置的重要性 5.6. 实例说明 六、设备文件…...
【StableDiffusion容器化部署】分步指南
使用Docker部署和管理Stable Diffusion环境可以有效解决依赖冲突、环境隔离和可移植性问题。以下是分步指南和相关技术细节: 1. 基础环境准备 1.1 安装Docker和GPU支持 安装Docker Engine:参考官方文档配置NVIDIA Container Toolkit:# 安装…...
2.11 sqlite3数据库【数据库的相关操作指令、函数】
练习: 将 epoll 服务器 客户端拿来用 客户端:写一个界面,里面有注册登录 服务器:处理注册和登录逻辑,注册的话将注册的账号密码写入数据库,登录的话查询数据库中是否存在账号,并验证密码是否正确…...
安装 Ollama 需要哪些步骤?(windows+mac+linux+二进制+Docker)
安装 Ollama 的步骤根据操作系统不同会有所差异,以下是针对不同操作系统的详细安装指南: Windows 系统 下载安装包:访问 Ollama 官方下载页面,下载适用于 Windows 的安装程序 OllamaSetup.exe。运行安装程序:双击下载的安装包,按照提示完成安装。默认安装路径为 C:\User…...
【力扣】148.排序链表
AC截图 题目 思路 基本情况处理: 如果链表为空 (head NULL) 或者链表仅有一个节点 (head->next NULL),则链表已经是有序的,直接返回头节点 head。 分割链表: 使用快慢指针法找到链表的中间节点。slow 指针每次前进一格&…...
Springboot框架扩展功能的使用
Spring Boot 提供了许多扩展点,允许开发者在应用程序的生命周期中插入自定义逻辑。这些扩展点可以帮助你更好地控制应用程序的行为,例如在启动时初始化数据、在关闭时释放资源、或者自定义配置加载逻辑。以下是 Spring Boot 中常见的扩展点: …...