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

揭秘关于TFRcord的五脏六腑

揭秘关于TFRcord的五脏六腑

前言:本篇文章将演示如何创建、解析和使用tf.Example消息,以及如何在.tfrecord文件之间对tf.Example消息进行序列化、写入和读取。

教程讲解使用的都是结构化数据,文章最后还会演示如果将图片写成.tfrecord文件,这在同个数据集用于不同模型情景之下非常有用。

官网文档是从讲原理,然后再展现示例。我觉得这种方式很容易劝退小白,因为原理晦涩难懂。这里先展示示例,然后再肢解示例,先总体再细分的思想

希望能让读者更容易理解和接受

一、如何将标量输入值变成协议消息

这里先不解释什么是协议消息,先看示例,后解释

# todo 导入相应工具包
import tensorflow as tfimport numpy as np
import IPython.display as display# todo 为了讲解,模拟生成一些数据
# 这里准备生成10000个元素
n_observations = int(1e4)# 随机生成10000个True和False布尔值
feature0 = np.random.choice([False, True], n_observations)# 随机生成10000个0-5的整数
feature1 = np.random.randint(0, 5, n_observations)# 随机生成10000个值是以下字符串的字符串
strings = np.array([b'cat', b'dog', b'chicken', b'horse', b'goat'])
feature2 = strings[feature1]# 随机生成10000个01正太分布数据,数据是浮点型
feature3 = np.random.randn(n_observations)# todo 下面分别演示将字符串类型标量、浮点型标量、整数型标量转换成协议消息
# todo 这些方法可以复制过去直接使用
def _bytes_feature(value):"""输入string / byte类型数据,返回bytes_list类型的协议消息"""if isinstance(value, type(tf.constant(0))):value = value.numpy() # BytesList won't unpack a string from an EagerTensor.return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value]))  # 先记住这个写法,这个写法是TF官网推荐的写法def _float_feature(value):"""输入float / double类型数据,返回float_list类型的协议消息"""return tf.train.Feature(float_list=tf.train.FloatList(value=[value]))def _int64_feature(value):"""输入bool / enum / int / uint.类型数据,返回int64_list类型的协议消息"""return tf.train.Feature(int64_list=tf.train.Int64List(value=[value]))# todo 通过调用上面的方法可以做到将相应类型的标量转换成协议消息了
print(_bytes_feature(b'test_string'))  # 字符串
print(_bytes_feature(u'test_bytes'.encode('utf-8')))  # 二进制bytesprint(_float_feature(np.exp(1)))  # 浮点型,自然数eprint(_int64_feature(True))  # 布尔型
print(_int64_feature(1))  # 整型

结果如下。结果展示的就是协议消息的“样子”,协议消息就是长这样,协议消息对应的值就是value里面的值

bytes_list {value: "test_string"
}bytes_list {value: "test_bytes"
}float_list {value: 2.7182817459106445
}int64_list {value: 1
}int64_list {value: 1
}

二、如何将协议消息变成二进制字符串

接着上面代码的延续,先不解释什么是二进制字符串,读者先阅读一遍代码的注释

# todo 将浮点型标量转成协议消息
feature = _float_feature(np.exp(1))# todo 使用方法SerializeToString(),将协议消息变成二进制字符串
string_010 = feature.SerializeToString()print(string_010)  # 结果是:   b'\x12\x06\n\x04T\xf8-@'"""
b'\x12\x06\n\x04T\xf8-@'
就是二进制字符串的样子
你可以简单把它理解成字符串
"""

三、如何将协议消息变成字典协议消息

字典型的协议消息如下,读者先看一遍代码的注释,再进行理解一遍

# todo 构建不同类型的协议消息
bytes_fea = _bytes_feature(b'test_string')  # 字符串协议消息float_fea = _float_feature(np.exp(1))  # 浮点型协议消息int64_fea = _int64_feature(1)  # 整数型协议消息# todo 将协议消息变成字典型协议消息
dict_fea = {'featrue0':bytes_fea,'featrue1':float_fea,'featrue2':int64_fea,
}
"""
说明:
dict_fea就是字典型协议消息,其中字典的key可以顺便自己命名,而字典的value就是协议消息
"""

字典型协议消息就是字典的value就是协议消息的字典

四、如何将字典协议消息变成二进制字符串

做法就是将字典协议消息转成特征消息,因为特征消息是协议消息的一种,所以可以将特征消息根据方法SerializeToString()变成二进制字符串

# todo 构建不同类型的协议消息
bytes_fea = _bytes_feature(b'test_string')  # 字符串协议消息float_fea = _float_feature(np.exp(1))  # 浮点型协议消息int64_fea = _int64_feature(1)  # 整数型协议消息# todo 将协议消息变成字典型协议消息
dict_fea = {'featrue0':bytes_fea,'featrue1':float_fea,'featrue2':int64_fea,
}# todo 将协议消息变成特征消息,代码就是这么写的,读者根据官网推荐这些写法这么写即可
example_proto = tf.train.Example(features=tf.train.Features(feature=dict_fea))# todo 将特征消息转成二进制字符串
bytes_string = example_proto.SerializeToString()
print(bytes_string)

结果如下。显示的就是字典协议消息的二进制字符串

b'\nF\n\x1b\n\x08featrue0\x12\x0f\n\r\n\x0btest_string\n\x14\n\x08featrue1\x12\x08\x12\x06\n\x04T\xf8-@\n\x11\n\x08featrue2\x12\x05\x1a\x03\n\x01\x01'

五、关于TFRecord文件各种疑问

  • 什么是TFRecord文件

    TFRecord 格式是一种用于存储二进制字符串记录序列的简单格式。

  • 为什么要用TFRecord文件

    通过tfrecord文件建立的数据管道Dataset对象读数的性能更好

  • TFRecord格式详细信息

    TFRecord 文件包含一系列记录。该文件只能按顺序读取。

    每条记录包含一个字节字符串(用于数据有效负载),外加数据长度,以及用于完整性检查的 CRC32C(使用 Castagnoli 多项式的 32 位 CRC)哈希值。

    每条记录会存储为以下格式:

    uint64 length uint32 masked_crc32_of_length byte   data[length] uint32 masked_crc32_of_data
    

    将记录连接起来以生成文件。此处对 CRC 进行了说明,且 CRC 的掩码为:

    masked_crc = ((crc >> 15) | (crc << 17)) + 0xa282ead8ul
    

    注:不需要在 TFRecord 文件中使用 tf.Exampletf.Example 只是将字典序列化为字节字符串的一种方法。文本行、编码的图像数据,或序列化的张量(使用 tf.io.serialize_tensor,或在加载时使用 tf.io.parse_tensor)。有关更多选项,请参阅 tf.io 模块。

六、TFRecord文件如何存储数据

TFRecord文件存储的是二进制字符串,二进制字符串由协议消息或者是字典协议消息生成,协议消息又由标量或者是向量生成。

所以TFRecord存储的二进制字符串相当于存储了真实的数据

之所以要通过协议消息、字典协议消息来存储这些数据,是因为这样子可以提高数据的复用率和使用效率

七、将numpy数据存储成TFRecord格式文件

读者可以直接阅读代码的注释.从上往下阅读即可,不需要觉得很难

# todo 导入相应工具包
import tensorflow as tfimport numpy as np
import IPython.display as display# todo 为了讲解,模拟生成一些数据
# 这里准备生成10000个元素
n_observations = int(1e4)# 随机生成10000个True和False布尔值
feature0 = np.random.choice([False, True], n_observations)# 随机生成10000个0-5的整数
feature1 = np.random.randint(0, 5, n_observations)# 随机生成10000个值是以下字符串的字符串
strings = np.array([b'cat', b'dog', b'chicken', b'horse', b'goat'])
feature2 = strings[feature1]# 随机生成10000个01正太分布数据,数据是浮点型
feature3 = np.random.randn(n_observations)# todo 下面分别演示将字符串类型标量、浮点型标量、整数型标量转换成协议消息
# todo 这些方法可以复制过去直接使用
def _bytes_feature(value):"""输入string / byte类型数据,返回bytes_list类型的协议消息"""if isinstance(value, type(tf.constant(0))):value = value.numpy() # BytesList won't unpack a string from an EagerTensor.return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value]))  # 先记住这个写法,这个写法是TF官网推荐的写法def _float_feature(value):"""输入float / double类型数据,返回float_list类型的协议消息"""return tf.train.Feature(float_list=tf.train.FloatList(value=[value]))def _int64_feature(value):"""输入bool / enum / int / uint.类型数据,返回int64_list类型的协议消息"""return tf.train.Feature(int64_list=tf.train.Int64List(value=[value]))def serialize_example(feature0, feature1, feature2, feature3):"""输入标量,转成字典协议消息,转成特征消息,转成二进制字符串"""# 构建字典协议消息feature = {'feature0': _int64_feature(feature0),'feature1': _int64_feature(feature1),'feature2': _bytes_feature(feature2),'feature3': _float_feature(feature3),}# Create a Features message using tf.train.Example.example_proto = tf.train.Example(features=tf.train.Features(feature=feature))return example_proto.SerializeToString()# todo 将二进制字符串写进tfrecord文件中
filename = './test.tfrecord'
with tf.io.TFRecordWriter(filename) as writer:  # 构建一个写入对象的上下文for i in range(n_observations):  # 循环写入example = serialize_example(feature0[i], feature1[i], feature2[i], feature3[i])writer.write(example)
<ipython-input-62-e109c8c4da87>:38: DeprecationWarning: In future, it will be an error for 'np.bool_' scalars to be interpreted as an indexreturn tf.train.Feature(int64_list=tf.train.Int64List(value=[value]))

从上面可以看出来,上面的代码需要循环写入数据,速度比较慢,下面介绍一种速度更加快速的写入方法

八、通过Dataset将numpy数据存储成TFRecord格式文件

过程代码解释了原理,并且这些代码都可以进行复用,请读者认真消化

# todo 导入相应工具包
import tensorflow as tfimport numpy as np
import IPython.display as display# todo 为了讲解,模拟生成一些数据
# 这里准备生成10000个元素
n_observations = int(1e4)# 随机生成10000个True和False布尔值
feature0 = np.random.choice([False, True], n_observations)# 随机生成10000个0-5的整数
feature1 = np.random.randint(0, 5, n_observations)# 随机生成10000个值是以下字符串的字符串
strings = np.array([b'cat', b'dog', b'chicken', b'horse', b'goat'])
feature2 = strings[feature1]# 随机生成10000个01正太分布数据,数据是浮点型
feature3 = np.random.randn(n_observations)# todo 下面分别演示将字符串类型标量、浮点型标量、整数型标量转换成协议消息
# todo 这些方法可以复制过去直接使用
def _bytes_feature(value):"""输入string / byte类型数据,返回bytes_list类型的协议消息"""if isinstance(value, type(tf.constant(0))):value = value.numpy() # BytesList won't unpack a string from an EagerTensor.return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value]))  # 先记住这个写法,这个写法是TF官网推荐的写法def _float_feature(value):"""输入float / double类型数据,返回float_list类型的协议消息"""return tf.train.Feature(float_list=tf.train.FloatList(value=[value]))def _int64_feature(value):"""输入bool / enum / int / uint.类型数据,返回int64_list类型的协议消息"""return tf.train.Feature(int64_list=tf.train.Int64List(value=[value]))def serialize_example(feature0, feature1, feature2, feature3):"""输入标量,转成字典协议消息,转成特征消息,转成二进制字符串"""# 构建字典协议消息feature = {'feature0': _int64_feature(feature0),'feature1': _int64_feature(feature1),'feature2': _bytes_feature(feature2),'feature3': _float_feature(feature3),}# Create a Features message using tf.train.Example.example_proto = tf.train.Example(features=tf.train.Features(feature=feature))return example_proto.SerializeToString()# todo 构建Dataset对象
features_dataset = tf.data.Dataset.from_tensor_slices((feature0, feature1, feature2, feature3))def tf_serialize_example(f0,f1,f2,f3):tf_string = tf.py_function(  # py_function函数将python函数转成可以通过tf计算图进行运算的函数,提升速度的关键就是在此serialize_example,(f0,f1,f2,f3),  # 传到函数serialize_example的参数tf.string)      # 指定函数serialize_example返回值的类型return tf.reshape(tf_string, ()) # 返回结果# todo 构建一个生成器
def generator():for features in features_dataset:yield serialize_example(*features)if True:# todo 通过map函数将函数tf_serialize_example作用到features_dataset对象中的每个元素中,生成一个新的Dataset对象serialized_features_dataset = features_dataset.map(tf_serialize_example)
else:# todo 也可以直接通过生成器构建需要的Dataset对象serialized_features_dataset = tf.data.Dataset.from_generator(generator, # 可调用的生成器函数output_types=tf.string, # 输出数据的类型output_shapes=()   # 输出数据的形状)# todo 通过Dataset对象,将数据存储成TFRecord格式文件
filename = 'test.tfrecord'
writer = tf.data.experimental.TFRecordWriter(filename)
writer.write(serialized_features_dataset)

九、通过Dataset对象读取TFRecord格式文件

过程代码解释了原理,并且这些代码都可以进行复用,请读者认真消化。定义特征描述,这个非常重要,主要是定义了特征描述的形状和类型


# 将TFRecord文件读成Dataset对象
filenames = [filename]
raw_dataset = tf.data.TFRecordDataset(filenames)# todo 定义特征描述,这个非常重要,格式如下,主要是定义了特征描述的形状和类型
feature_description = {'feature0': tf.io.FixedLenFeature([], tf.int64, default_value=0),'feature1': tf.io.FixedLenFeature([], tf.int64, default_value=0),'feature2': tf.io.FixedLenFeature([], tf.string, default_value=''),'feature3': tf.io.FixedLenFeature([], tf.float32, default_value=0.0),
}def _parse_function(example_proto):# 将二进制字符串转成实际的存储数据return tf.io.parse_single_example(example_proto, feature_description)# 运用map函数将函数_parse_function作用到Dataset对象的每个元素里面
parsed_dataset = raw_dataset.map(_parse_function)# parsed_dataset对象的每个元素就是真实的存储数据
for parsed_record in parsed_dataset.take(10):print(repr(parsed_record))break

结果如下

{'feature0': <tf.Tensor: shape=(), dtype=int64, numpy=1>, 'feature1': <tf.Tensor: shape=(), dtype=int64, numpy=2>, 'feature2': <tf.Tensor: shape=(), dtype=string, numpy=b'chicken'>, 'feature3': <tf.Tensor: shape=(), dtype=float32, numpy=-0.10460473>}

10、欢迎关注,下期讲解使用TFRecord文件读取和写入图像数据

相关文章:

揭秘关于TFRcord的五脏六腑

揭秘关于TFRcord的五脏六腑 前言&#xff1a;本篇文章将演示如何创建、解析和使用tf.Example消息&#xff0c;以及如何在.tfrecord文件之间对tf.Example消息进行序列化、写入和读取。 教程讲解使用的都是结构化数据&#xff0c;文章最后还会演示如果将图片写成.tfrecord文件&am…...

【Shell学习笔记】3.Shell 传递参数及数组

前言 本章介绍Shell的传递参数和数组。 Shell 传递参数 我们可以在执行 Shell 脚本时&#xff0c;向脚本传递参数&#xff0c;脚本内获取参数的格式为&#xff1a;$n。n 代表一个数字&#xff0c;1 为执行脚本的第一个参数&#xff0c;2 为执行脚本的第二个参数&#xff0c;…...

【终结Bug】ModuleNotFoundError: No module named ‘cv2’

解决方案&#xff1a; 打开 cmd键入 pip install opencv_python -i https://pypi.tuna.tsinghua.edu.cn/simple...

SQL Server2008详细安装步骤(保姆式教程)

安装包下载 链接&#xff1a;https://pan.baidu.com/s/1Rjx4DHJBeCW2asC_4Kzo6Q?pwdchui 提取码&#xff1a;chui 安装过程 1.解压后使用管理员身份打开安装程序 2.选择全新安装或向现有安装添加新功能 3.确认 4.输入产品密钥&#xff08;上方网盘安装包里有&#xff0…...

Linux常用操作

Linux常用操作 前言常用命令&#xff1a;一些操作命令&#xff1a;前言 本文是笔者在使用cadence的过程中&#xff0c;操作linux的笔记&#xff0c;仅记录个人常用&#xff0c;持续更新 常用命令&#xff1a; &#xff08;1&#xff09;高频&#xff1a;会了这几个就能在文件…...

Golang 处理parquet文件实战教程

Parquet是Apache基金会支持的项目&#xff0c;是面向列存储二进制文件格式。支持不同类型的压缩方式&#xff0c;广泛用于数据科学和大数据环境&#xff0c;如Hadoop生态。 本文主要介绍Go如何生成和处理parquet文件。 创建结构体 首先创建struct&#xff0c;用于表示要处理…...

腾讯TIM实现即时通信 v3+ts实践

目录 初始化sdk 功能描述 初始化 准备 SDKAppID 调用初始化接口 监听事件 发送消息 创建消息 创建文本消息 登录登出 功能描述 登录 登出 销毁 登录设置 获取会话列表 功能描述 获取会话列表 获取全量的会话列表 历史消息 功能描述 拉取消息列表 分页拉取…...

华为OD机试 - 回文字符串(Java JS Python)

题目描述 如果一个字符串正读和反渎都一样(大小写敏感),则称它为一个「回文串」,例如: leVel是一个「回文串」,因为它的正读和反读都是leVel;同理a也是「回文串」art不是一个「回文串」,因为它的反读tra与正读不同Level不是一个「回文串」,因为它的反读leveL与正读不…...

APP测试的7大注意点。

1. 运行 1&#xff09; App安装完成后的试运行&#xff0c;可正常打开软件。 2&#xff09; App打开测试&#xff0c;是否有加载状态进度提示。 3&#xff09; App⻚面间的切换是否流畅&#xff0c;逻辑是否正确。 4&#xff09; 注册 同表单编辑⻚面 用户名密码⻓度 …...

设计模式-第4章(装饰模式)

装饰模式装饰模型装饰模式示例商场收银程序&#xff08;简单工厂策略装饰模式实现&#xff09;装饰模式总结装饰模型 装饰模式&#xff08;Decorator&#xff09;&#xff0c;动态地给一个对象添加一些额外的职责&#xff0c;就增加功能来说&#xff0c;装饰模式比生成子类更为…...

【算法设计-分治】快速幂与龟速乘

文章目录1. 快速幂2. 龟速乘3. 快速幂取模4. 龟速乘取模5. 快速幂取模优化1. 快速幂 算法原理&#xff1a; 计算 311&#xff1a; 311 (35)2 x 335 (32)2 x 332 3 x 3仅需计算 3 次&#xff0c;而非 11 次 计算 310&#xff1a; 310 (35)235 (32)2 x 332 3 x 3仅需计算…...

基于新一代kaldi项目的语音识别应用实例

本文是由郭理勇在第二届SH语音技术研讨会和第七届Kaldi技术交流会上对新一代kaldi项目在学术及“部署”两个方面报告的内容上的整理。如果有误&#xff0c;欢迎指正。 文字整理丨李泱泽 编辑丨语音小管家 喜报&#xff1a;新一代Kaldi团队三篇论文均被语音顶会ICASSP-2023接…...

【GO】31.grpc 客户端负载均衡源码分析

这篇文章是记录自己查看客户端grpc负载均衡源码的过程&#xff0c;并没有太详细的讲解&#xff0c;参考价值不大&#xff0c;可以直接跳过&#xff0c;主要给自己看的。一.主要接口&#xff1a;Balancer Resolver1.Balancer定义Resolver定义具体位置为1.grpc源码对解析器(resol…...

PTA L1-058 6翻了(详解)

前言&#xff1a;内容包括&#xff1a;题目&#xff0c;代码实现&#xff0c;大致思路&#xff0c;代码解读 题目&#xff1a; “666”是一种网络用语&#xff0c;大概是表示某人很厉害、我们很佩服的意思。最近又衍生出另一个数字“9”&#xff0c;意思是“6翻了”&#xff0…...

【Origin科研绘图】如何快速绘制一个折线图 ||【前端特效】爱心篇 之 幸好有你 || 泰坦尼克号——乘客生存与否 预测 || PyCharm使用介绍

🎯作者主页:追光者♂ 🌸个人简介:在读计算机专业硕士研究生、CSDN-人工智能领域新星创作者🏆、2022年CSDN博客之星人工智能领域TOP4🌟、阿里云社区专家博主🏅 【无限进步,一起追光!】 🍎欢迎点赞👍 收藏⭐ 留言📝 🌿本篇,首先是:基于科研绘图工具O…...

一文解读电压放大器(电压放大器原理)

关于电压放大器的科普知识&#xff0c;之前讲过很多&#xff0c;今天为大家汇总一篇文章来详细的讲解电压放大器&#xff0c;希望大家对于电压放大器能有更清晰的认识。电压放大器是什么&#xff1a;电压放大器是一种常用的电子器件&#xff0c;它的主要作用是把输入信号的振幅…...

线上监控诊断神器arthas

目录 什么是arthas 常用命令列表 1、dashboard仪表盘 2、heapdump dumpJAVA堆栈快照 3、jvm 4、thread 5、memory 官方文档 安装使用 1、云安装arthas 2、获取需要监控进程ID 3、运行arthas 4、进入仪表盘 5、其他命令使用查看官方文档 什么是arthas arthas是阿…...

@Import注解的原理

此注解是springboot自动注入的关键注解&#xff0c;所以拿出来单独分析一下。 启动类的run方法跟进去最终找到refresh方法&#xff1b; 这里直接看这个org.springframework.context.support.AbstractApplicationContext#refresh方法即可&#xff0c;它下面有一个方法 invoke…...

平台总线开发(id和设备树匹配)

目录 一、ID匹配之框架代码 二、ID匹配之led驱动​​​​​​​ 三、设备树匹配 四、设备树匹配之led驱动 五、一个编写驱动用的宏 一、ID匹配之框架代码 id匹配&#xff08;可想象成八字匹配&#xff09;&#xff1a;一个驱动可以对应多个设备 ------优先级次低 注意事项…...

TS泛型,原来就这?

一、泛型是什么&#xff1f;有什么作用&#xff1f; 当我们定义一个变量不确定类型的时候有两种解决方式&#xff1a; 使用any 使用any定义时存在的问题&#xff1a;虽然知道传入值的类型但是无法获取函数返回值的类型&#xff1b;另外也失去了ts类型保护的优势 使用泛型 泛型…...

Leetcode 3576. Transform Array to All Equal Elements

Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接&#xff1a;3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到&#xf…...

解锁数据库简洁之道:FastAPI与SQLModel实战指南

在构建现代Web应用程序时&#xff0c;与数据库的交互无疑是核心环节。虽然传统的数据库操作方式&#xff08;如直接编写SQL语句与psycopg2交互&#xff09;赋予了我们精细的控制权&#xff0c;但在面对日益复杂的业务逻辑和快速迭代的需求时&#xff0c;这种方式的开发效率和可…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)

服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务

通过akshare库&#xff0c;获取股票数据&#xff0c;并生成TabPFN这个模型 可以识别、处理的格式&#xff0c;写一个完整的预处理示例&#xff0c;并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务&#xff0c;进行预测并输…...

postgresql|数据库|只读用户的创建和删除(备忘)

CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...

(二)原型模式

原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...

页面渲染流程与性能优化

页面渲染流程与性能优化详解&#xff08;完整版&#xff09; 一、现代浏览器渲染流程&#xff08;详细说明&#xff09; 1. 构建DOM树 浏览器接收到HTML文档后&#xff0c;会逐步解析并构建DOM&#xff08;Document Object Model&#xff09;树。具体过程如下&#xff1a; (…...

vue3 定时器-定义全局方法 vue+ts

1.创建ts文件 路径&#xff1a;src/utils/timer.ts 完整代码&#xff1a; import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...

什么是EULA和DPA

文章目录 EULA&#xff08;End User License Agreement&#xff09;DPA&#xff08;Data Protection Agreement&#xff09;一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA&#xff08;End User License Agreement&#xff09; 定义&#xff1a; EULA即…...

今日科技热点速览

&#x1f525; 今日科技热点速览 &#x1f3ae; 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售&#xff0c;主打更强图形性能与沉浸式体验&#xff0c;支持多模态交互&#xff0c;受到全球玩家热捧 。 &#x1f916; 人工智能持续突破 DeepSeek-R1&…...