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

浅谈SIMD、向量化处理及其在StarRocks中的应用

前言

单指令流多数据流(SIMD)及其衍生出来的向量化处理技术已经有了相当的历史,并且也是高性能数据库、计算引擎、多媒体库等组件的标配利器。笔者在两年多前曾经做过一次有关该主题的内部Geek分享,但可能是由于这个topic离实际研发场景比较远,当时听者寥寥。昨晚翻看硬盘中存的各种资料,翻到了相关内容,遂整理出来,顺便添加一些新东西。

SIMD

SIMD即"single instruction, multiple data"的缩写,是Flynn分类法对计算机的四大分类之一。它本质上是采用一个控制器来控制多个处理器,同时对一组数据中的每一条分别执行相同的操作,从而实现空间上的并行性的技术。

可见,“单指令流”指的是同时只能执行一种操作,“多数据流”则指的是在一组同构的数据(通常称为vector,即向量)上进行操作,如下图所示,其中PU = processing unit。

SIMD在现代计算机体系中的应用十分广泛,最典型的则是在GPU的像素处理流水线中。举个例子,如果要更改一整幅图像的亮度,只需要取出各像素的RGB值存入向量单元(向量单元很宽,可以存储多个像素的数据),再同时将它们做相同的加减操作即可,效率很高。SIMD和MIMD流水线是GPU微架构的基础,就不再展开聊了。

那么CPU是如何实现SIMD的呢?答案是扩展指令集。Intel的第一版SIMD扩展指令集称为MMX,于1997年发布。后来至今的改进版本有SSE(Streaming SIMD Extensions)、AVX(Advanced Vector Extensions),以及AMD的3DNow!等。我们可以通过cpuid类软件获得处理器对SIMD扩展指令集的支持信息,例如随便找一台服务器,执行cat /proc/cpuinfo命令,观察flags域,如下。

processor   : 63
vendor_id   : GenuineIntel
cpu family  : 6
model       : 79
model name  : Intel(R) Xeon(R) CPU E5-2683 v4 @ 2.10GHz
stepping    : 1
microcode   : 0xb000040
cpu MHz     : 1272.637
cache size  : 40960 KB
physical id : 1
siblings    : 32
core id     : 15
cpu cores   : 16
apicid      : 63
initial apicid  : 63
fpu     : yes
fpu_exception   : yes
cpuid level : 20
wp      : yes
flags       : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch epb cat_l3 cdp_l3 invpcid_single intel_pt ssbd ibrs ibpb stibp tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm cqm rdt_a rdseed adx smap xsaveopt cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local dtherm ida arat pln pts md_clear spec_ctrl intel_stibp flush_l1d
bogomips    : 4204.62
clflush size    : 64
cache_alignment : 64
address sizes   : 46 bits physical, 48 bits virtual
power management:

并不仅有Intel或者服务器处理器才支持SIMD扩展指令集,下图以笔者家用游戏PC中的AMD锐龙9 7950X3D处理器为例,可见同样支持。

下面简要介绍SSE指令集。

SSE指令集

SSE指令集是MMX的继任者,其第一版早在Pentium III时代就被引入了。随着新指令的扩充,又有了SSE2、SSE3、SSSE3、SSE4(包含4.1和4.2)等新版本。

SSE指令集以8个128位寄存器为基础,命名为XMM0~XMM7。在AMD64(即64位扩展)指令集中,又新增了XMM8~XMM15。一个XMM寄存器原本只能存储一种数据类型,即4个32位单精度浮点数,后来SSE2又扩展到能够存储以下类型:

  • 2个64位双精度浮点数
  • 2个64位 / 4个32位 / 8个16位整数
  • 16个字节或字符

SIMD指令分为两大类,一是标量(scalar)指令,二是打包(packed)指令。标量指令只对XMM寄存器中的最低位数据进行计算,打包指令则是对所有数据进行计算。下图示出SSE1中,单精度浮点数乘法的标量和打包运算。

观察指令助记符,mul表示乘法,接下来的s表示标量,p表示打包,最后一个s则表示类型为单精度浮点数(single-precision)。由图也可以发现,打包指令才是真正SIMD的,而标量指令是SISD的。

再举个小栗子,如果我们要实现两个4维向量v1和v2的加法,只需要三条SSE指令就够了。

movaps xmm0, [v1] ;xmm0 = v1.w | v1.z | v1.y | v1.x addps xmm0, [v2]  ;xmm0 = v1.w+v2.w | v1.z+v2.z | v1.y+v2.y | v1.x+v2.xmovaps [vec_res]  ;xmm0

注意数据移动指令movaps中的a表示对齐(align)。第一条指令的意思就是通过[v1]直接寻址得到向量的起点,并分别按照0、4、8、16字节的偏移量写入XMM0寄存器的低到高四个域。在数据本身已经按照16字节对齐的情况下,调用这种指令效率非常高。从寄存器写入内存也是同理的,如下图。

除了存取和数学运算指令外,SSE还提供了常用的比较、位移、位运算、类型转换、预取等指令。由此可见,SIMD对于那些严重依赖流程控制(flow control heavy)的任务,即有大量分支、跳转和条件判断的任务则不太适用。也就是说,SIMD主要被用来优化可并行计算的简单场景,以及可能被频繁调用的基础逻辑。

接下来再快速看一眼AVX指令集。

AVX指令集

AVX指令集是基于SSE指令集的扩展,在Sandy Bridge时代提出,Haswell时代又新增了AVX2。AVX指令集支持的数据类型与SSE本质上相同,但寄存器宽度翻了一倍,由128位来到了256位,称为YMM寄存器(SSE的XMM寄存器可以视作是YMM的低128位),如下图所示。

以下是vhaddpd指令的图示,它分别将两个YMM寄存器中的64位浮点数水平相加(d代表double),然后将结果交错存入第三个YMM寄存器中。

相比SSE,AVX支持更高效的位重排、三操作数指令(如上,即C = A + B)、非对齐访存等特性。StarRocks的SIMD优化主要就是基于AVX2做的,所以在部署文档的第一步,就是检查部署环境的CPU是否支持AVX2指令集。

说了这么多,最后以StarRocks为例简单看看SIMD扩展指令集在实际工程中的运用。

StarRocks向量化处理示例

如何运用SIMD指令集呢?主要有以下3种方法:

  • 直接编写内嵌汇编语句;
  • 利用厂商提供的扩展库函数。Intel将这类函数统称为Intrinsics,官方提供的速查手册见这里;
  • 开启编译器的优化(如GCC/G++的-msse2-mavx2等),编译器会自动将符合条件的情景(最简单的如数组相加、矩阵相乘)编译为SIMD指令。

向量化处理涉及到大量的case by case优化,在StarRocks BE源码中随处可见。我们可以查找形如#ifdef __SSE2__的宏定义,或者根据手册查找Intrinsic函数对应的头文件,如AVX2的头文件是<immintrin.h>,以此类推。

下面选取两段示例代码简单分析。

基于SSE2的向量化大小写转换

先上代码。

template <char CA, char CZ>
static inline void vectorized_toggle_case(const Bytes* src, Bytes* dst) {const size_t size = src->size();// resize of raw::RawVectorPad16 is faster than std::vector because of// no initializationstatic_assert(sizeof(Bytes::value_type) == 1, "Underlying element type must be 8-bit width");static_assert(std::is_trivially_destructible_v<Bytes::value_type>,"Underlying element type must have a trivial destructor");Bytes buffer;buffer.resize(size);uint8_t* dst_ptr = buffer.data();char* begin = (char*)(src->data());char* end = (char*)(begin + size);char* src_ptr = begin;
#if defined(__SSE2__)static constexpr int SSE2_BYTES = sizeof(__m128i);const char* sse2_end = begin + (size & ~(SSE2_BYTES - 1));const auto a_minus1 = _mm_set1_epi8(CA - 1);const auto z_plus1 = _mm_set1_epi8(CZ + 1);const auto flips = _mm_set1_epi8(32);for (; src_ptr > sse2_end; src_ptr += SSE2_BYTES, dst_ptr += SSE2_BYTES) {auto bytes = _mm_loadu_si128((const __m128i*)src_ptr);// the i-th byte of masks is set to 0xff if the corresponding byte is// between a..z when computing upper function (A..Z when computing lower function),// otherwise set to 0;auto masks = _mm_and_si128(_mm_cmpgt_epi8(bytes, a_minus1), _mm_cmpgt_epi8(z_plus1, bytes));// only flip 5th bit of lowcase(uppercase) byte, other bytes keep verbatim._mm_storeu_si128((__m128i*)dst_ptr, _mm_xor_si128(bytes, _mm_and_si128(masks, flips)));}
#endif// only flip 5th bit of lowcase(uppercase) byte, other bytes keep verbatim.// i.e.  'a' and 'A' are 0b0110'0001 and 0b'0100'0001 respectively in binary form,// whether 'a' to 'A' or 'A' to 'a' conversion, just flip 5th bit(xor 32).for (; src_ptr < end; src_ptr += 1, dst_ptr += 1) {*dst_ptr = *src_ptr ^ (((CA <= *src_ptr) & (*src_ptr <= CZ)) << 5);}// move semanticsdst->swap(reinterpret_cast<Bytes&>(buffer));
}

根据手册简要介绍一下代码中涉及到的Intrinsic函数:

  • _mm_loadu_si128(mem_addr):从内存地址mem_addr处加载128位的整形数据;
  • _mm_storeu_si128(mem_addr, a):将128位的整形数据a存入内存地址mem_addr处;
  • _mm_set1_epi8(a):将8位整形数据a广播到128位,即写入16个a
  • _mm_cmpgt_epi8(a, b):按8位比较a和b两个128位整形数,若a的对应8位比b的对应8位大,则填充对应位为全1,否则填充全0;
  • _mm_and_si128(a, b)_mm_xor_si128(a, b):两个128位数据之前按位与和按位异或。

由此可见,整个流程是一次性加载16个字符,然后并行判断字符是否在[A-Za-z]的范围内(注意掩码masks),若符合条件,则根据大小写字母ASCII码值相差32的特性,对字符的第5位做翻转(flips10000)即可。

基于AVX2的向量化过滤

在StarRocks的底层,过滤器(Filter)是一个预分配空间的、无符号8位整形数的向量,用于表示WHEREHAVING子句的真值,每一位的取值为0或1,即表示为假或真。Filter和列(Column)是共生的,每种Column的实现都提供了对应的filter_range方法来过滤数据。以BinaryColumnBase为例,其filter_range方法的源码如下。

template <typename T>
size_t BinaryColumnBase<T>::filter_range(const Filter& filter, size_t from, size_t to) {auto start_offset = from;auto result_offset = from;uint8_t* data = _bytes.data();#ifdef __AVX2__const uint8_t* f_data = filter.data();int simd_bits = 256;int batch_nums = simd_bits / (8 * (int)sizeof(uint8_t));__m256i all0 = _mm256_setzero_si256();while (start_offset + batch_nums < to) {__m256i f = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(f_data + start_offset));uint32_t mask = _mm256_movemask_epi8(_mm256_cmpgt_epi8(f, all0));if (mask == 0) {// all no hit, pass} else if (mask == 0xffffffff) {// all hit, copy all// copy dataT size = _offsets[start_offset + batch_nums] - _offsets[start_offset];memmove(data + _offsets[result_offset], data + _offsets[start_offset], size);// set offsets, try vectorizedT* offset_data = _offsets.data();for (int i = 0; i < batch_nums; ++i) {// TODO: performance, all sub one same offset ?offset_data[result_offset + i + 1] = offset_data[result_offset + i] +offset_data[start_offset + i + 1] - offset_data[start_offset + i];}result_offset += batch_nums;} else {// skip not hit row, it's will reduce compare when filter layout is sparse,// like "00010001...", but is ineffective when the filter layout is dense.uint32_t zero_count = Bits::CountTrailingZerosNonZero32(mask);uint32_t i = zero_count;while (i < batch_nums) {mask = zero_count < 31 ? mask >> (zero_count + 1) : 0;T size = _offsets[start_offset + i + 1] - _offsets[start_offset + i];// copy datememmove(data + _offsets[result_offset], data + _offsets[start_offset + i], size);// set offsets_offsets[result_offset + 1] = _offsets[result_offset] + size;zero_count = Bits::CountTrailingZeros32(mask);result_offset += 1;i += (zero_count + 1);}}start_offset += batch_nums;}
#endiffor (auto i = start_offset; i < to; ++i) {if (filter[i]) {DCHECK_GE(_offsets[i + 1], _offsets[i]);T size = _offsets[i + 1] - _offsets[i];// copy datamemmove(data + _offsets[result_offset], data + _offsets[i], size);// set offsets_offsets[result_offset + 1] = _offsets[result_offset] + size;result_offset++;}}this->resize(result_offset);return result_offset;
}

还是根据手册简要介绍一下代码中涉及到的Intrinsic函数:

  • _mm256_setzero_si256():返回一个256位的全0位图;
  • _mm256_loadu_si256(mem_addr):从内存地址mem_addr处加载256位的整形数据;
  • _mm256_cmpgt_epi8(a, b):按8位比较a和b两个256位整形数,若a的对应8位比b的对应8位大,则填充对应位为全1,否则填充全0;
  • _mm256_movemask_epi8(a):根据256位整形数a的每个8位组的最高位生成掩码,一共32位长,返回一个int型结果。

由此可见,BE通过AVX2一次性加载一批32个真值进行判断。生成的掩码若为全0,表示全部不满足过滤条件,若为0xffffffff,则表示全部满足过滤条件,并拷贝结果。若是0、1混杂的情况,则调用内置的__builtin_ctz()函数取得掩码中末尾0的个数,然后直接跳过这些0位对应的数据,只将1对应的有效数据拷贝。如此循环,直到剩余的真值不满32个,循环遍历完即可。

The End

晚安。

相关文章:

浅谈SIMD、向量化处理及其在StarRocks中的应用

前言 单指令流多数据流(SIMD)及其衍生出来的向量化处理技术已经有了相当的历史&#xff0c;并且也是高性能数据库、计算引擎、多媒体库等组件的标配利器。笔者在两年多前曾经做过一次有关该主题的内部Geek分享&#xff0c;但可能是由于这个topic离实际研发场景比较远&#xff0…...

【ML】Image Augmentation)的作用、使用方法及其分类

图像增强&#xff08;Image Augmentation&#xff09;的作用、使用方法及其分类 1. 图像增强的定义2. 图像增强的作用3. 什么时候使用图像增强&#xff1f;4. 图像增强详细方法分类梳理4.1 图像增强方法列表4.2 边界框增强方法5. 参考资料 yolov3&#xff08;一&#xff1a;模型…...

设计模式六大原则(一)--单一职责原则

1. 简介 1.1. 概述 一个类或模块应该只负责完成一项任务或承担一个责任。如果一个类或模块承担了多个职责,那么当需要修改其中一个职责的功能时,就可能会对其他职责产生影响,从而导致代码耦合度增加,维护起来更加困难。 1.2. 主要特点 单一职责原则(Single Responsibi…...

c语言学习,malloc()函数分析

1&#xff1a;malloc() 函数说明&#xff1a; 申请配置size大小内存空间 2&#xff1a;函数原型&#xff1a; void *malloc(size_t size) 3&#xff1a;函数参数&#xff1a; 参数size&#xff0c;为申请内存大小 4&#xff1a;返回值&#xff1a; 配置成功则返回指针&#…...

【运维项目经历|041】上云项目-物理机迁移到阿里云

🍁博主简介: 🏅云计算领域优质创作者 🏅2022年CSDN新星计划python赛道第一名 🏅2022年CSDN原力计划优质作者 ​ 🏅阿里云ACE认证高级工程师 ​ 🏅阿里云开发者社区专家博主 💊交流社区:CSDN云计算交流社区欢迎您的加入! 目录 项目名称 项目背景 项目目标 项…...

分组并合并其它列的非空值 --Excel难题#83

Excel第1列是分类&#xff0c;第2-42列是平行的多个数据项列&#xff0c;下表用部分列示例。数据有X或null两种情况&#xff0c;同一个分类的同一列数据偶尔有重复。 ABCDE1IDCriteria1Criteria2Criteria3Criteria42FirstValueX3FirstValueX4FirstValueX5FirstValueX6SecondVa…...

VM相关配置及docker

NAT——VMnet8网卡 桥接——WLAN/网线 仅主机——VMnet1网卡 docker与虚拟机的区别 启动docker服务 systemctl start docker 重启 systemctl start docker关闭docker服务 systemctl stop docker.servicedocker的两大概念 镜像&#xff1a;images&#xff0c;应用程序的静态文…...

Redis中Set数据类型常用命令

目录 1. 添加元素 2. 移除元素 3. 检查成员是否存在 4. 获取集合成员 5. 获取集合成员数量 6. 随机获取集合中的一个成员 7. 集合运算 8. 集合的移值 9. 提供集合的随机元素 在Redis中&#xff0c;Set是一种无序且不重复的字符串集合。 1. 添加元素 SADD key member [member ..…...

mysql误删数据恢复记录

背景 1、数据库版本 5.7.36&#xff0c;由于误操作删掉了表的所有数据&#xff0c;但是数据库备份每天凌晨进行、只能从备份恢复昨日的全量数据&#xff0c;当日的数据将会丢失 查看binlog配置 binlog配置 [mysqld] #设置日志三种格式&#xff1a;STATEMENT、ROW、MIXED 。 bi…...

论文阅读:Real-time Controllable Denoising for Image and Video

这篇文章是 CVPR 2023 的一篇文章&#xff0c;探讨了在图像与视频降噪中&#xff0c;如何实时控制降噪强度的问题。 Abstract 图像或者视频降噪&#xff0c;是在细节与平滑度之间的一个微妙的平衡&#xff0c;因为噪声与细节都属于高频信息&#xff0c;降噪在去除噪声的同时&…...

【Kubernetes】虚拟 IP 与 Service 的代理模式

虚拟 IP 与 Service 的代理模式 1.userspace 代理模式2.iptables 代理模式3.IPVS 代理模式 由于 Service 的默认发布类型是 ClusterlP&#xff0c;因此也可以把 ClusterIP 地址叫作 虚拟 IP 地址。在 Kubernetes 创建 Service 时&#xff0c;每个节点上运行的 kube-proxy 会自动…...

深度学习·Pytorch

以下代码源自李沐 自定义模块类 继承module类 继承nn.Module重写构造函数前向传播 class MLP(nn.Module):# 用模型参数声明层。这里&#xff0c;我们声明两个全连接的层def __init__(self):# 调用MLP的父类Module的构造函数来执行必要的初始化。# 这样&#xff0c;在类实例…...

fastzdp_sqlmodel新增get_first和is_exitsts方法

说明 经过fastzdp_login的整合&#xff0c;我们发现&#xff0c;fastzdp_sqlmodel还可以继续封装两个便捷的方法。 get_first&#xff1a;获取查询结果集中的第一条数据is_exitsts&#xff1a;判断数据是否已存在 封装get_first方法 def get_first(engine, model, query_di…...

嵌入式软件--数电基础 DAY 3

一、二进制 &#xff08;1&#xff09;文字表述 二进制数只能取0&#xff0c;1两个数字&#xff0c;逢二进一。 通过二进制表达文字。如战争时代的电报。 通过电灯泡的亮灭传递出信息。可以对灯亮和灯灭富裕一些含义&#xff0c;就能传达出想要的消息。 这就是编码和解码两…...

【生成式人工智能-十五-经典的影像生成方法-GAN】

经典的影像生成方法-GAN GANDiscriminatorGenerator还需要加入额外信息么 GAN可以加在其他模型上面我们可以用影像生成模型做什么&#xff1f; 前面讲过VAE和Flow-based以及diffusion Model &#xff0c;今天讲最后一种经典的生成方法GAN。 GAN 前面讲的几种模型都是用加入额外…...

python 已知x+y=8 求x*y*(x-y)的最大值

先用导数求解 已知xy8 求xy(x-y)的最大值 令y8-x 则 f(x)x⋅(8−x)⋅(x−(8−x))x⋅(8−x)⋅(2x−8) 导数方程为 f(x)-3x^2 24x - 32 求方程 − 3 x 2 24 x − 32 0 -3x^2 24x - 32 0 −3x224x−320 的根。 首先&#xff0c;我们可以尝试对方程进行因式分解。观察…...

windows平台的postgresql主从数据库流备份

主: 操作系统:windows10 数据库版本&#xff1a;postgresql-16.2 ip&#xff1a;192.168.3.254 从: 操作系统&#xff1a;windows10 数据库版本&#xff1a;postgresql-16.2 ip&#xff1a;192.168.3.253 配置主库 配置 pg_hba.conf 文件 在 pg 的安装目录下&#xff0c;找到 …...

Spring 常见设计模式

什么是设计模式&#xff1f; 设计模式&#xff08;Design pattern&#xff09;是为解决软件设计中通用问题而被提出的一套指导性思想。它是一种被反复验证、经过实践证明并被广泛应用的代码设计经验和思想总结&#xff0c;可以帮助开发者通过一定的模式来快速的开发高质量、可维…...

优化大量数据导出到Excel的内存消耗(二):如果数据超出Excel单表上限,则进行分表

优化前&#xff1a;优化大量数据导出到Excel的内存消耗_大文件异步导出 内存占用高-CSDN博客 写Excel文件报错&#xff1a;Invalid row number (1048576) outside allowable range (0..1048575) 写入Excel时遇到IllegalArgumentException&#xff0c;原因是超出允许的最大行数…...

rustrover打开会报Error: Invalid toolchain

如果 cargo --version 正常输出&#xff0c;但在使用 RustRover 时出现“Invalid toolchain”错误&#xff0c;可能是由于 RustRover 工具链配置有问题或路径指向错误。 解决步骤&#xff1a; 1. 检查 RustRover 的工具链配置 打开 RustRover&#xff0c;进入 Preferences 或…...

docker-compose 安装canal

创建 Canal 配置文件 /conf/canal.properties mkdir -p conf/ touch /conf/canal.properties # canal.properties# tcp bind ip canal.ip 0.0.0.0 canal.port 11111 canal.metrics.pull.port 11112# zookeeper 集群配置 canal.zkServers canal.zookeeper.sessionTimeout…...

Unity动画模块 之 3D Rig页签

​本文仅作笔记学习和分享&#xff0c;不用做任何商业用途本文包括但不限于unity官方手册&#xff0c;unity唐老狮等教程知识&#xff0c;如有不足还请斧正​​ 1.Rig页签 Rig 选项卡 - Unity 手册&#xff0c;rig是设置骨骼与替身系统的&#xff0c;工作流程如下 Avatar是什么…...

【蓝桥杯冲刺省一,省一看这些就够了-Java版本】蓝桥杯日期问题相关模板以及练习题

蓝桥杯历年省赛真题 点击链接免费加入题单 日期问题 java.time Java 中用于处理日期和时间的主要类位于 java.time 包中。以下是一些常用的类和其功能的简要介绍&#xff1a; LocalDate&#xff1a;表示日期。它提供了获取年、月、日以及日期之间比较的方法。 LocalDate to…...

【经典算法】BFS_FloodFill算法

目录 1&#xff0c; 算法介绍2&#xff0c;算法原理和代码实现(含题目链接)733.图像渲染200.岛屿的数量695.岛屿的最大面积130.被围绕的区域 3&#xff0c; 算法总结 1&#xff0c; 算法介绍 FloodFill(洪水灌溉) 算法介绍&#xff1a; 假设一个 4 * 4 的方格代表一块土地&am…...

RocketMQ之Topic主题详解

Topic概念定义 主题&#xff1a;RocketMQ中消息传输和存储的顶层容器&#xff0c;用于标识同类业务中逻辑的消息&#xff0c;可理解为消息的分类&#xff0c;主题消息的分类取决于业务&#xff0c;要发送的业务消息最好单独是一个Topic主题&#xff0c;以保证互相不被干扰Topi…...

实战OpenCV之图像显示

基础入门 OpenCV提供的功能非常多&#xff0c;图像显示是最基础也是最直观的一部分。它让我们能够直观地看到算法处理后的效果&#xff0c;对于调试和验证都至关重要。在OpenCV中&#xff0c;图像显示主要依赖于以下四个关键的数据结构和函数。 1、Mat类。这是OpenCV中最基本的…...

I2C的10-bit地址空间

10-bit地址空间&#xff1a; I2C支持 10-bit的设备地址&#xff0c;此时的时序如下图所示&#xff1a; 在 10-bit地址的 I2C系统中&#xff0c;需要两个帧来传输 slave的地址。第一个帧的前 5个 bit固定为 b11110&#xff0c;后接 slave地址的高 2位&#xff0c;第 8位仍然是 …...

TinyWebserver的复现与改进(6):定时器处理非活动连接

如果客户端长时间没有动作&#xff0c;会占用了许多连接资源&#xff0c;严重影响服务器的性能。因此需要通过实现一个服务器定时器&#xff0c;处理这种非活跃连接&#xff0c;释放连接资源。 定时器处理流程 SIGALARM触发&#xff1a;整个流程开始于一个 SIGALARM 信号&…...

ThinkPHP5 5.0.23 远程代码执行漏洞

目录 1、启动环境 2、漏洞利用 3、更改传参方式 4、修改参数 5、发送数据 1、启动环境 docker-compose up -d 2、访问靶机ip端口号8080 2、漏洞利用 使用burpsuite抓包软件抓包 3、更改传参方式 将 GET传参改为POST传参 4、修改参数 url参数 /index.php?scaptcha post参…...

C++鼠标键盘操作自动化

C鼠标键盘操作自动化 #pragma once #include <Windows.h> enum KEYS{A 65,W87,S83,D68,SHIFTVK_LSHIFT,ALT18,Tilde 126,//~TABVK_TAB,B66,SPACEVK_SPACE,ESCVK_ESCAPE,Q81 }; enum MOUSE {ML,MW,MR//左&#xff0c;中&#xff0c;右 }; class simulator//模拟器 { pu…...

多个主流Python GUI库全面解析,助你用Python轻松构建精美界面

Python 作为一门易学易用的编程语言&#xff0c;在各个领域都拥有广泛的应用。而 GUI (Graphical User Interface) 编程更是让 Python 变得更加灵活&#xff0c;可以帮助我们创建各种各样的桌面应用&#xff0c;为用户提供直观的交互体验。本文将介绍几个Python GUI 编程中常用…...

Kotlin学习-01创建kotlin学习

安装idea https://www.jetbrains.com/zh-cn/ 创建项目 选择kotlin 修改Main.kt fun main() {print("Hello World!") }运行...

Java、python、php版的企业单位考勤打卡管理系统的设计与实现(源码、调试、LW、开题、PPT)

&#x1f495;&#x1f495;作者&#xff1a;计算机源码社 &#x1f495;&#x1f495;个人简介&#xff1a;本人 八年开发经验&#xff0c;擅长Java、Python、PHP、.NET、Node.js、Android、微信小程序、爬虫、大数据、机器学习等&#xff0c;大家有这一块的问题可以一起交流&…...

在IntelliJ IDEA中使用Git推送项目

去gitee网站注册用户 gitee网站地址:https://gitee.com/ github网站地址:https://github.com/ 一、创建仓库 以下以gitee为例进行介绍&#xff0c;github操作雷同。 1、创建仓库 点击页面右上方的"“并选择"创建仓库” 2、设置仓库相关信息 首先输入仓库名&…...

CNN代码实战

CNN的原理 从 DNN 到 CNN &#xff08;1&#xff09;卷积层与汇聚 ⚫ 深度神经网络 DNN 中&#xff0c;相邻层的所有神经元之间都有连接&#xff0c;这叫全连接&#xff1b;卷积神经网络 CNN 中&#xff0c;新增了卷积层&#xff08;Convolution&#xff09;与汇聚&#xff08…...

迁移学习代码复现

一、前言 说来可能令人难以置信,迁移学习技术在实践中是非常简单的,我们仅需要保留训练好的神经网络整体或者部分网络,再在使用迁移学习的情况下把保留的模型重新加载到内存中,就完成了迁移的过程。之后,我们就可以像训练普通神经网络那样训练迁移过来的神经网络了。 我们…...

Elasticsearch(ES)常用命令

常用运维命令 一、基本命令1.1、查看集群的健康状态1.2、查看节点信息1.3、查看索引列表1.4、创建索引1.5、删除索引1.6、关闭索引1.7、打开索引1.8、查看集群资源使用情况&#xff08;各个节点的状态&#xff0c;包括磁盘&#xff0c;heap&#xff0c;ram的使用情况&#xff0…...

C/C++ 不定参函数

C语言不定参函数 函数用法总结 Va_list 作用&#xff1a;类型定义&#xff0c;生命一个变量&#xff0c;该变量被用来访问传递给不定参函数的可变参数列表用法&#xff1a;供后续函数进调用&#xff0c;通过该变量访问参数列表 typedefchar* va_list; va_start 作用&#xff…...

C语言——函数专题

1.概念 在C语言中引入函数的概念&#xff0c;有些翻译为子程序。C语言中的函数就是一个完成某项特定任务的一小段代码&#xff0c;这个代码是有特殊的写法和调用方法的。一般我们可以分为两种函数&#xff1a;库函数和自定义函数。 2.库函数 C语言国际标准ANSIC规定了一些常…...

springboot打可执行jar包

1. pom文件如下 <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><m…...

【SQL】科目种类

目录 题目 分析 代码 题目 表: Teacher ------------------- | Column Name | Type | ------------------- | teacher_id | int | | subject_id | int | | dept_id | int | ------------------- 在 SQL 中&#xff0c;(subject_id, dept_id) 是该表的主键。 该表…...

【深度学习】【语音】TTS,最新TTS模型概览,扩散模型TTS,MeloTTS、StyleTTS2、Matcha-TTS

文章目录 基础介绍对比基础介绍 MeloTTS: MeloTTS 是 MyShell.ai 开发的一个多语言语音合成模型,支持包括英语、西班牙语、法语、中文、日语和韩语等多种语言。它以高质量的语音合成为特色,尤其擅长处理中英混合内容。该模型优化了在 CPU 上的实时推理能力,使其在多种应用场…...

【论文笔记】LION: Linear Group RNN for 3D Object Detection in Point Clouds

原文链接&#xff1a;https://arxiv.org/abs/2407.18232 简介&#xff1a;Transformer在3D点云感知任务中有二次复杂度&#xff0c;难以进行长距离关系建模。线性RNN则计算复杂度较低&#xff0c;适合进行长距离关系建模。本文提出基于窗口的网络线性组RNN&#xff08;即对分组…...

打造高可用集群的基石:深度解析Keepalived实践与优化

高可用集群 集群类型 集群类型主要分为负载均衡集群&#xff08;LB&#xff09;、高可用集群&#xff08;HA&#xff09;和高性能计算集群&#xff08;HPC&#xff09;三大类。每种集群类型都有其特定的应用场景和优势。 1. 负载均衡集群&#xff08;LB&#xff09; 负载均衡集…...

Web大学生网页作业成品——环保主题介绍网页网站设计与实现(HTML+CSS)(5个页面)

&#x1f389;&#x1f389;&#x1f389; 常见网页设计作业题材有**汽车、环保、明星、文化、国家、抗疫、景点、人物、体育、植物、公益、图书、节日、游戏、商城、旅游、家乡、学校、电影、动漫、非遗、动物、个人、企业、美食、婚纱、其他**等网页设计题目, 可满足大学生网…...

Qt登录窗口设计

widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QIcon> //图标类 #include <QPushButton> #include <QLineEdit> //行编辑 #include <QLabel> #include <QTextEdit> #include <QMovie>class Widge…...

探索数据矿藏:我的AI大模型与数据挖掘实战经验分享

&#x1f680; 探索数据矿藏&#xff1a;我的AI大模型与数据挖掘实战经验分享 &#x1f496; 前言&#xff1a;数据的金矿&#xff0c;AI的翅膀 在人工智能的浪潮中&#xff0c;我有幸作为项目负责人&#xff0c;带领团队深入挖掘数据的潜力&#xff0c;利用AI大模型的力量&am…...

linux C语言strcat函数及相关函数

讯飞星火 strcat函数是C语言中的一个字符串处理函数,用于将一个字符串追加到另一个字符串的末尾。它的原型如下: char *strcat(char *dest, const char *src);参数说明: dest:目标字符串,即要将src字符串追加到这个字符串的末尾。src:源字符串,即要追加到dest字符串末…...

使用 sort 进行文本文件处理

sort 使用经验笔记 一、简介 sort 是一个命令行工具&#xff0c;用于对文本文件中的行进行排序。它广泛应用于 Unix/Linux 系统中&#xff0c;可以用来对文件的内容进行简单的排序操作&#xff0c;也可以与其他命令结合使用来完成更复杂的任务。 二、基本用法 排序文件: sor…...

HarmonyOS笔记4:从云数据库获取数据

移动应用获取数据的方式主要有&#xff1a; 1.从网络中获取数据接口API。 2.从华为云数据库获取云数据库的资源。 3.从移动终端直接获取本地的数据 在HarmonyOS笔记3中已经完成了方式一从网络中获取数据接口API的方式。在本篇笔记中&#xff0c;将讨论从云数据库中获取数据。 因…...