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

Transformers实战05-模型量化

文章目录

  • 简介
    • 主要类型
    • 量化的优点
    • 量化的缺点
    • 量化过程
      • 量化过程
      • 反量化过程
    • 精度和参数
  • 量化实例
    • bitsandbytes
      • 安装bitsandbytes
      • 4bit量化(加载)
      • 8bit量化(加载)
      • 验证效果

简介

模型量化(Model Quantization)是一种优化技术,旨在减少机器学习模型的计算资源需求和存储空间,同时在精度损失最小化的前提下提高推理效率。量化通过将模型权重和激活函数的数值从高精度(如 32 位浮点数)转换为低精度(如 8 位整数),显著减少了模型大小和计算复杂度。

主要类型

  1. 静态量化(Post-Training Quantization, PTQ)

    • 在模型训练完成后进行量化。
    • 通过分析训练数据的分布,将权重和激活函数映射到低精度表示。
    • 不需要重新训练模型。
    • 适用于对性能影响较小的场景。
  2. 动态量化(Dynamic Quantization)

    • 在推理时动态地将浮点数转换为低精度整数。
    • 在运行过程中对激活函数进行量化。
    • 比静态量化更简单,因为不需要分析训练数据。
    • 对推理速度有显著提升,尤其是对模型输入依赖较少的层(如全连接层)。
  3. 量化感知训练(Quantization-Aware Training, QAT)

    • 在训练过程中模拟量化影响。
    • 模型在训练过程中考虑量化误差,以便在量化后保持更高的精度。
    • 比静态量化和动态量化需要更多的计算资源,但精度损失最小。
    • 适用于对精度要求较高的应用。

这里例子就演示下动态量化,bitsandbytes本身以上三种都支持。

量化的优点

  • 减小模型大小:通过将权重和激活函数表示从 32 位浮点数转换为 8 位整数,模型大小可以显著减少。
  • 加快推理速度:低精度运算速度更快,可以显著提高推理效率。
  • 降低内存带宽需求:低精度表示占用更少的内存,减少了内存带宽的需求。

量化的缺点

  • 精度损失:由于数值表示的精度降低,模型可能会经历一定程度的精度损失,具体程度取决于模型结构和数据分布。
  • 复杂性增加:在某些情况下,量化过程可能会增加模型部署的复杂性,尤其是需要进行量化感知训练时。

量化过程

以下过程只是一种最简单的思路,方便理解,实际要比这更复杂。

量化过程

  1. 确定值域: 首先,确定要量化的数据的值域范围。例如,假设我们有一组数据的值域为 [ m i n , m a x ] [min,max] [min,max]

  2. 确定量化级别: 确定量化的级别或分辨率,这决定了将值域划分成多少个区间。在4位整数的情况下,共有 2 4 = 16 2^4=16 24=16 个可能的值。

  3. 线性映射: 将原始数据映射到4位整数的范围内。通常使用线性映射来实现,计算公式如下:
    quantized_value = original_value − min max − min × ( number of levels − 1 ) \text{quantized\_value} = \frac{\text{original\_value} - \text{min}}{\text{max} - \text{min}} \times (\text{number of levels} - 1) quantized_value=maxminoriginal_valuemin×(number of levels1)

  4. 这里的 number of levels 是16(对应4位整数的值域范围)。

反量化过程

解码反量化: 在使用量化数据进行计算之前,需要将其解码回原始的数据表示形式(如32位浮点数或其他高精度表示)。解码公式通常为:
original_value = quantized_value × max − min number of levels − 1 + min \text{original\_value} = \text{quantized\_value} \times \frac{\text{max} - \text{min}}{\text{number of levels} - 1} + \text{min} original_value=quantized_value×number of levels1maxmin+min
这里的 quantized_value是是量化后的4位整数值,min和max是原始数据的最小值和最大值。

两个不同的原始值在量化后可能相同,被还原为同一个值。这种情况表明精度损失是不可避免的。为了减少这种精度损失带来的影响,通常采取以下策略:

  1. 增加量化级别: 增加量化级别(如使用8位、16位量化)以减少不同原始值被量化为同一个值的概率。

  2. 量化感知训练(Quantization-aware training): 在训练过程中模拟量化误差,以提高模型在量化后的精度表现。

  3. 非线性量化: 使用对数量化或其他非线性量化方法,使得量化更适应数据的分布特性,从而减少精度损失。

  4. 精细调节量化参数: 通过精细调整量化的最小值、最大值和比例因子,尽量减少量化误差对关键值的影响。

精度和参数

模型中每个参数常见的存储类型包括:

  • FP32(32-bit Floating Point): 每个参数占用 4 字节(32 位),单精度浮点数(32位浮点数),范围大约: [ − 3.4 × 1 0 38 , 3.4 × 1 0 38 ] [-3.4 \times 10^{38}, 3.4 \times 10^{38}] [3.4×1038,3.4×1038]
  • FP16(16-bit Floating Point): 每个参数占用 2 字节(16 位),半精度浮点数使用16位(1位符号、5位指数、10位尾数),FP16的数值范围大约是 [−65504,65504],大约 3 位有效数字。
  • INT8(8-bit Integer): 每个参数占用 1 字节(8 位),将模型的权重和激活值量化为8位整数(范围通常是0到255),相对于32位浮点数,精度的损失较小。8-bit量化比4-bit提供更好的精度,并且通常可以更接近原始模型的性能。
  • INT4(4-bit Integer): 每个参数占用4位,将模型的权重和激活值量化为4位整数(范围通常是-8到7或者0到15),因此相对于32位浮点数,它的精度显著降低。这种量化可以显著减小模型的大小和计算需求,但可能会损失一定的模型精度。

如何获取某个模型的精度了

import torch
from transformers import AutoModel, BertTokenizer
model_name="bert-base-chinese" #bert-base-uncased
model=AutoModel.from_pretrained(model_name)
#获取模型参数的精度
"""FP32(32-bit Floating Point): 每个参数占用 4 字节(32 位)。FP16(16-bit Floating Point): 每个参数占用 2 字节(16 位)。INT8(8-bit Integer): 每个参数占用 1 字节(8 位)。
"""
dtype=list(model.parameters())[0].dtype
print("精度:",dtype)
total_params = sum(p.numel() for p in model.parameters())
dtype_to_bytes = {torch.float32: 4,  # FP32: 4字节torch.float16: 2,  # FP16: 2字节torch.int8: 1,     # INT8: 1字节torch.int32: 4,    # INT32: 4字节torch.int64: 8,    # INT64: 8字节torch.float64: 8,  # FP64 (double): 8字节
}
model_size = total_params * dtype_to_bytes[dtype]
print(f'Model size: {model_size / (1024**2):.2f} MB')

输出

精度: torch.float32
Model size: 390.12 MB

量化实例

bitsandbytes

bitsandbytes 通过 PyTorch 的 k 位量化技术使大型语言模型的访问变得可行。bitsandbytes 提供了三个主要功能以显著降低推理和训练时的内存消耗:

  • 8 位优化器采用区块式量化技术,在极小的内存成本下维持 32 位的表现。
  • LLM.Int() 或 8 位量化使大型语言模型推理只需一半的内存需求,并且不会有任何性能下降。该方法基于向量式的量化技术将大部分特性量化到 8 位,并且用 16 位矩阵乘法单独处理异常值。
  • QLoRA 或 4 位量化使大型语言模型训练成为可能,它结合了几种节省内存的技术,同时又不牺牲性能。该方法将模型量化至 4 位,并插入一组可训练的低秩适应(LoRA)权重来允许训练。

安装bitsandbytes

bitsandbytes 仅支持 CUDA 版本 11.0 - 12.5 的 CUDA GPU。

!pip install -U bitsandbytes
!pip install transformers
!pip install accelerate

4bit量化(加载)

加载并量化一个模型到4位,并使用bfloat16数据类型进行计算:

您使用 bnb_4bit_compute_dtype=torch.bfloat16,这意味着计算过程中会反量化使用 bfloat16 数据类型,而存储时则可能使用4位表示。这解释了为什么您看到的 dtype 仍然是 fp16 或者 bfloat16。

BigScience 是一个全球性的开源AI研究合作项目,旨在推动大型语言模型(LLM)的发展。bloom-1b7 是 BigScience 项目下的一部分,具体来说,是一个包含约17亿参数的语言模型。

import torch
from transformers import AutoModelForCausalLM, BitsAndBytesConfig
model_name="bigscience/bloom-1b7" 
quantization_config = BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_compute_dtype=torch.bfloat16)
model = AutoModelForCausalLM.from_pretrained(model_name,device_map="auto",
)
model_4bit = AutoModelForCausalLM.from_pretrained(model_name,device_map="auto",quantization_config=quantization_config,
)
dtype=list(model.parameters())[0].dtype
print("原始精度:",dtype)
dest_dtype=list(model_4bit.parameters())[0].dtype
print("量化精度:",dest_dtype)# 检查模型的量化配置
print("量化配置:", model_4bit.config.quantization_config)def print_model_info(model):total_params = 0for name, param in model.named_parameters():total_params += param.numel()#print(f"Total parameters: {total_params / 1e6}M")return total_paramstotal_model_size=print_model_info(model)
total_model_4bit_size=print_model_info(model_4bit)
print("模型参数个数:",total_model_size)
print("量化后的模型参数个数:",total_model_4bit_size)dtype_to_bytes = {torch.float32: 4,  # FP32: 4字节torch.float16: 2,  # FP16: 2字节torch.int8: 1,     # INT8: 1字节torch.int32: 4,    # INT32: 4字节torch.int64: 8,    # INT64: 8字节torch.float64: 8,  # FP64 (double): 8字节
}
model_size = total_model_size * dtype_to_bytes[dtype]
model_size = total_model_size * dtype_to_bytes[dtype]
print(f'origin Model size: {model_size / (1024**2):.2f} MB')
model_size = total_model_4bit_size * dtype_to_bytes[dest_dtype]
print(f'quan Model size: {model_size / (1024**2):.2f} MB')model_4bit.save_pretrained("/tmp/p")
model.save_pretrained("/tmp/o")

输出:

原始精度: torch.float32
量化精度: torch.float16
量化配置: BitsAndBytesConfig {"_load_in_4bit": true,"_load_in_8bit": false,"bnb_4bit_compute_dtype": "bfloat16","bnb_4bit_quant_storage": "uint8","bnb_4bit_quant_type": "fp4","bnb_4bit_use_double_quant": false,"llm_int8_enable_fp32_cpu_offload": false,"llm_int8_has_fp16_weight": false,"llm_int8_skip_modules": null,"llm_int8_threshold": 6.0,"load_in_4bit": true,"load_in_8bit": false,"quant_method": "bitsandbytes"
}模型参数信息: 1722408960
量化后的模型参数信息: 1118429184
origin Model size: 6570.47 MB
quan Model size: 2133.23 MB

总的参数个数减少。这通常是由于量化过程中进行了优化或者参数压缩的操作。
量化在深度学习中通常是指将模型中的浮点数参数转换为更低精度的整数或定点数表示,以节省内存和提高计算效率。

为啥量化和原模型的dtype都是fp16了,以下是对量化模型加载过程中 dtype 问题的一些解释:

  1. 参数存储与计算类型的区别

    • 存储时,模型参数可能被压缩或量化为较低位宽的整数类型(如4位整数)。
    • 加载时,为了方便后续计算,这些参数可能会被解码为较高精度的浮点类型(如 fp16bfloat16)。
  2. 量化过程的具体实现

    • 许多量化库在加载模型时,会将低位宽的量化参数解码为浮点类型,以便在计算时可以直接使用这些参数。
    • 这就是为什么即使您使用了 load_in_4bit=True,在加载后检查参数的 dtype 时仍然看到的是 fp16

通过查看模型保存的就可以确定了
查看量化的模型:

!ls /tmp/p -al --block-size=M | grep model

输出:

-rw-r--r-- 1 root root 1630M Aug  6 08:04 model.safetensors

可以看到我们之前在内存中打印的是2133.23(内存中计算还是会被反量化到bnb_4bit_compute_dtype指定类型,但是参数都是压缩后去掉了一些参数) ,存储后变成了1630M,比之前计算的少一些,说明存储使用了4bit。
在看下没有量化的模型:

!ls /tmp/o -al --block-size=M | grep model

输出了:

-rw-r--r-- 1 root root 4714M Aug  6 08:05 model-00001-of-00002.safetensors
-rw-r--r-- 1 root root 1857M Aug  6 08:05 model-00002-of-00002.safetensors
-rw-r--r-- 1 root root    1M Aug  6 08:05 model.safetensors.index.json

可以看到我们之前在内存中打印的是6570.47 MB ,存储后没变,分文件存储了4714M+1857M 。

8bit量化(加载)

代码和4bit相似,调整下配置即可

quantization_config = BitsAndBytesConfig(load_in_8bit=True)

同4bit代码,输出

原始精度: torch.float32
量化精度: torch.float16
量化配置: BitsAndBytesConfig {"_load_in_4bit": false,"_load_in_8bit": true,"bnb_4bit_compute_dtype": "float32","bnb_4bit_quant_storage": "uint8","bnb_4bit_quant_type": "fp4","bnb_4bit_use_double_quant": false,"llm_int8_enable_fp32_cpu_offload": false,"llm_int8_has_fp16_weight": false,"llm_int8_skip_modules": null,"llm_int8_threshold": 6.0,"load_in_4bit": false,"load_in_8bit": true,"quant_method": "bitsandbytes"
}模型参数信息: 1722408960
量化后的模型参数信息: 1722408960
origin Model size: 6570.47 MB
quan Model size: 3285.23 MB

可以看到8bit不需要指定内存计算的类型,量化内存计算精度默认就是fp16。
查看模型保存大小

!ls /tmp/p -al --block-size=M | grep model
#----------------------------------------------------------------------------------------------------
!ls /tmp/o -al --block-size=M | grep model

输出

-rw-r--r-- 1 root root 2135M Aug  6 08:30 model.safetensors
#----------------------------------------------------------------------------------------------------
-rw-r--r-- 1 root root 4714M Aug  6 08:30 model-00001-of-00002.safetensors
-rw-r--r-- 1 root root 1857M Aug  6 08:31 model-00002-of-00002.safetensors
-rw-r--r-- 1 root root    1M Aug  6 08:31 model.safetensors.index.json

验证效果

这里用之前的4bit模型来和原始模型比较

import timedef benchmark_model(model, input_text, tokenizer):inputs = tokenizer(input_text, return_tensors="pt").to(model.device)start_time = time.time()with torch.no_grad():outputs = model.generate(**inputs)# 解码并打印生成的文本generated_text = tokenizer.decode(outputs[0], skip_special_tokens=True)print("Generated text:", generated_text)end_time = time.time()inference_time = end_time - start_timeprint(f"Inference time: {inference_time:.2f} seconds")from transformers import AutoTokenizertokenizer = AutoTokenizer.from_pretrained(model_name)
input_text = "Hello, how are you?"
print("未量化模型性能测试:")
benchmark_model(model, input_text, tokenizer)
print("量化模型性能测试:")
benchmark_model(model_4bit, input_text, tokenizer)

输出

未量化模型性能测试:
Generated text: Hello, how are you? I hope you are doing well. I am a newbie in this
Inference time: 0.31 seconds
量化模型性能测试:
Generated text: Hello, how are you?"
"I'm fine," I said.
"I'm just a
Inference time: 0.62 seconds

这里看到量化的模型反而推理需要更多的时间,量化模型在理论上应该提高推理速度和减少内存占用,但在实际应用中,可能会因为多个因素导致性能下降。

相关文章:

Transformers实战05-模型量化

文章目录 简介主要类型量化的优点量化的缺点量化过程量化过程反量化过程 精度和参数 量化实例bitsandbytes安装bitsandbytes4bit量化(加载)8bit量化(加载)验证效果 简介 模型量化(Model Quantization)是一种优化技术,旨在减少机器学习模型的…...

【Python】bytes 和 bytearray 到底是什么类型呢?

bytes和bytearray同属于二进制序列类型,是常见的数值类型的一种。 bytes多用在在文件的读写、网络通信、数据编码/解码等场景用的比较多。 而bytearray在二进制数据处理、图像处理、内存映射文件和网络通信等场景用的比较多。 其中这两部分的主要差别: …...

Windows10上安装SQL Server 2022 Express

Microsoft SQL Server 2022 Express是一个功能强大且可靠的免费数据管理系统,可为轻量级网站和桌面应用程序提供丰富可靠的数据存储,为关系数据库: (1).LocalDB(SqlLocalDB):是Express的一种轻型版本,该版本具备所有可…...

C++11 异常

目录 0.前言 1.C语言传统错误处理方式 1.1使用返回值 1.2使用全局变量 1.3使用断言 1.4优缺点 2.C异常的概念 3.异常的使用 3.1异常的抛出和捕获 3.1.1异常的抛出和匹配原则 3.1.2在函数调用链中异常栈展开匹配原则 3.2异常的重新抛出 3.3异常安全 3.4异常规范 4.自定义异常体系…...

pip下载lap失败

把pip install lap改为pip intsall lapx...

【Material-UI】Button 中的点击事件处理(Handling clicks)详解

文章目录 一、点击事件处理基础1. 基本用法2. 事件处理器的传递 二、实际应用中的注意事项1. 事件处理逻辑的优化2. 避免过多的状态更新3. 使用合适的事件类型 三、关于文档中未提及的原生属性四、最佳实践1. 无障碍性2. 视觉反馈3. 防止重复点击 五、总结 在现代前端开发中&am…...

Spring Cache框架(AOP思想)+ Redis实现数据缓存

文章目录 1 简介1.1 基本介绍1.2 为什么要用 Spring Cache? 2 使用方法2.1 依赖导入(Maven)2.2 常用注解2.3 使用步骤2.4 常用注解说明1)EnableCaching2)CachePut3)Cacheable4)CacheEvict 3 注意…...

在Windows编程中,MFC\C++中如何在OnCopyData中传递Vector类型数据?

我们在通过 WM_COPYDATA 消息实现进程间通信时,发送char 数组或其他类型数组与发送vector是有区别的。 1、发送基础类型时,直接发送指针。 typedef struct tagMYSTRUCT {int nTest;wchar_t cTest[40] {0}; } MYSTRUCT, *PMYSTRUCT;MYSTRUCT stSend; s…...

Java常见面试题-01-java基础

文章目录 面向对象的特征Java 的基本数据类型有哪些JDK、JRE、JVM 的区别重载和重写的区别Java 中和 equals 的区别String、StringBuffer、StringBuilder 三者之间的区别接口和抽象类的区别是什么string 常用的方法有哪些什么是单例模式?有几种?什么是反…...

Python爬虫实战:利用代理IP爬取百度翻译

文章目录 一、爬取目标二、环境准备三、代理IP获取3.1 爬虫和代理IP的关系3.2 巨量IP介绍3.3 超值企业极速池推荐3.4 IP领取3.5 代码获取IP 四、爬虫代码实战4.1分析网页4.2 寻找接口4.3 参数构建4.4 完整代码 一、爬取目标 本次目标网站:百度翻译(http…...

Transformer学习之DETR

文章目录 1.算法简介1.1 算法主要贡献1.2 算法网络结构 2.损失函数设计2.1 二分图匹配(匈牙利算法)2.2 二分图匹配Loss_match2.3 训练Loss_Hungarian 3.网络核心模块3.1 BackBone模块3.2 空间位置编码(spatial positional encoding)3.2.1 输入与输出3.2.2 空间位置编码原理 3.3…...

场外个股期权是什么品种?可以交易哪些品种?

今天带你了解场外个股期权是什么品种?可以交易哪些品种?场外个股期权是指在场外市场进行交易的个股期权合约,与在交易所交易的标准化个股期权有所不同,它是由买方和卖方通过私下协商,而非通过公开交易所进行买卖和定价…...

每日学术速递8.5-3

1.BoostMVSNeRFs: Boosting MVS-based NeRFs to Generalizable View Synthesis in Large-scale Scenes 标题: BoostMVSNeRFs:将基于 MVS 的 NeRFs 提升到大规模场景中的可泛化视图合成 作者:Chih-Hai Su, Chih-Yao Hu, Shr-Ruei Tsai, Jie-…...

C#针对kernel32.dll的一些常规使用

1、前言 Window是一个复杂的系统,kernel32是一个操作系统的核心动态链接库文件。它提供了大量的API函数,提供了操作系统的基本功能。 2、Ini使用 Ini文件读写使用时,我们需要用到其中的一些函数对文件进行读写。 API: /// &l…...

电话营销机器人的优势

在人工智能的新趋势下,企业开始放弃传统外呼系统,转而使用电话销售机器人,那么使用机器人比坐席手动外呼好吗,真的可以代替人工坐席外呼吗,效率真的高吗? 1、 真人式语音 电话销售人员可以将自定义的话术…...

Oracle SQL Developer 连接第三方数据库

首先Oracle SQL Developer除了支持连接Oracle数据库外,还支持连接第三方数据库,包括: Amazon RedshiftHiveIBM DB2MySQLMicrosoft SQL ServerSybase Adaptive ServerPostgreSQLTeradataTimesTen 首先,你需要在菜单Tools > Pr…...

OSPF路由协议多区域

一、OSPF路由协议单区域的弊端 1、LSDB庞大,占用内存大,SPF计算开销大; 2、LSA洪泛范围大,拓扑变化影响范围大; 3、路由不能被汇总,路由表庞大,查找路由开销大。 二、如何解决OSPF单区域的问题? 引入划分区域 1、每个区域独立存储LSDB,划分区域减小了LSDB。 2、…...

8.5 C++

思维导图 试编程 提示并输入一个字符串&#xff0c;统计该字符中大写、小写字母个数、数字个数、空格个数以及其他字符个数 要求使用C风格字符串完成 #include <iostream> #include <array>using namespace std;int main() {cout << "请输入一个字符…...

MySQL —— 初始数据库

数据库概念 在学习数据库之前&#xff0c;大家保存数据要么是在程序运行期间&#xff0c;例如&#xff1a;在学习编程语言的时候&#xff0c;大家写过的管理系统&#xff0c;运用一些简单的数据结构&#xff08;例如顺序表&#xff09;来组织数据&#xff0c;可是程序一旦结束…...

【JVM】垃圾回收机制、算法和垃圾回收器

什么是垃圾回收机制 为了让程序员更加专注于代码的实现&#xff0c;而不用过多的考虑内存释放的问题&#xff0c;所以在Java语言中&#xff0c;有了自动的垃圾回收机制&#xff0c;也是我们常常提及的GC(Garbage Collection) 有了这个垃圾回收机制之后&#xff0c;程序员只需…...

大数据资源平台建设可行性研究方案(58页PPT)

方案介绍: 在当今信息化高速发展的时代&#xff0c;大数据已成为推动各行各业创新与转型的关键力量。为了充分利用大数据的潜在价值&#xff0c;构建一个高效、安全、可扩展的大数据资源平台显得尤为重要。通过本方案的实施企业可以显著提升数据处理能力、优化资源配置、促进业…...

PHP教育培训小程序系统源码

&#x1f680;【学习新纪元】解锁教育培训小程序的无限可能✨ &#x1f4da; 引言&#xff1a;教育培训新风尚&#xff0c;小程序来引领&#xff01; Hey小伙伴们&#xff0c;是不是还在为找不到合适的学习资源而烦恼&#xff1f;或是厌倦了传统教育模式的单调&#xff1f;今…...

吴恩达机器学习笔记

1.机器学习定义&#xff1a; 机器学习就是让机器从大量的数据集中学习&#xff0c;进而得到一个更加符合现实规律的模型&#xff0c;通过对模型的使用使得机器比以往表现的更好 2.监督学习&#xff1a; 从给定的训练数据集中学习出一个函数&#xff08;模型参数&#xff09;…...

React和Vue3 的 Diff 算法有什么区别

React 和 Vue 3 的 Diff 算法都有相似的目标&#xff0c;即在组件状态或属性变化时高效地更新 DOM&#xff0c;但它们在实现细节上有所不同。以下是 React 和 Vue 3 的 Diff 算法的主要区别&#xff1a; React 的 Diff 算法 1. 同层比较 React 使用的是同层比较策略&#xf…...

【vulhub靶场之rsync关】

一、使用nmap模块查看该ip地址有没有Rsync未授权访问漏洞 nmap -p 873 --script rsync-list-modules 加IP地址 查看到是有漏洞的模块的 二、使用rsync命令连接并读取文件 查看src目录里面的信息。 三、对系统中的敏感文件进行下载——/etc/passwd 执行命令&#xff1a; rsy…...

全球7大高质量海外代理IP对比大全

随着国内市场逐渐饱和&#xff0c;越来越多朋友私信我说打算开拓海外市场这片蓝海了&#xff01;海外代理IP作为解决这些需求的有效工具&#xff0c;帮助跨境企业或团队进行社媒管理、电商运营、市场调研、抓取数据、广告验证等等业务。但是&#xff0c;市场上提供的代理IP服务…...

对于原型链的理解

1.同一个构造函数的多个实例之间 无法共享属性&#xff08;创建多个实例的时候会造成资源浪费&#xff09; function Cat(name, color) {this.name name;this.color color;this.meow function () {console.log(miao);}; }var cat1 new Cat(LH, White); var cat2 new Cat(…...

Web开发:Vue中的事件小结

一、全选按钮checkbox <template><div id"checkboxs"><label><input id"selectAll" type"checkbox" v-model"selectAllChecked" change"selectAllItems">全部</label><label v-for"…...

基于Springboot的运行时动态可调的定时任务

配置类 import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;Configuration public class TaskSchedulerConfig {Bean(destroyMe…...

linux perf

perf是Linux性能分析工具的集合&#xff0c;它提供了丰富的命令来收集和分析程序运行时的性能数据。perf能够报告CPU使用率、缓存命中率、分支预测成功率等多种硬件级别的事件&#xff0c;同时也支持软件级别的事件&#xff0c;如页面错误、任务切换等。perf是理解程序性能瓶颈…...