CUDA C编程权威指南:1.1-CUDA基础知识点梳理

  主要整理了N多年前(2013年)学习CUDA的时候开始总结的知识点,好长时间不写CUDA代码了,现在LLM推理需要重新学习CUDA编程,看来出来混迟早要还的。

1.CUDA
解析:2007年,NVIDIA推出CUDA(Compute Unified Device Architecture,统一计算设备架构)这个编程模型,目的是为了在应用程序中充分利用CPU和GPU各自的优点,实现CPU/GPU联合执行。这种联合执行的需要已经在最新的集中编程模型(OpenCL,OpenACC,C++ AMP)中体现出来了。

2.并行编程语言和模型
解析:使用比较广泛的是为可扩展的集群计算设计的消息传递接口(Message Passing Interface,MPI)和为共享存储器的多处理器系统设计的OpenMP。目前,很多HPC(High-Performance Computing)集群采用的都是异构的CPU/GPU节点模型,也就是MPI和CUDA的混合编程,来实现多机多卡模型。目前,支持CUDA的编程语言有C,C++,Fortran,Python,Java [2]。CUDA采用的是SPMD(Single-Program Multiple-Data,单程序多数据)的并行编程风格。

3.数据并行性,任务并行性
解析:任务并行性通常对应用进行任务分解得到。例如,对一个需要做向量加法和矩阵-向量乘法的简单应用来说,每个操作可以看作一个任务。如果这两个任务可以独立地执行,那么就能得到任务并行性。

4.CUDA对C中函数声明的扩展
解析:

(1)__device__ float DeviceFunc():在设备上执行,并且只能从设备上调用。
(2)__global__ float KernelFunc():在设备上执行,并且只能从主机上调用。
(3)__host__ float HostFunc():在主机上执行,并且只能从主机上调用。

说明:如果在函数声明时没有指定CUDA扩展关键字,则默认的函数是主机函数。

5.thread,block,grid,warp,sp,sm
解析:
(1)grid、block、thread:在利用CUDA进行编程时,一个grid分为多个block,而一个block分为多个thread。
(2)sp:最基本的处理单元,最后具体的指令和任务都是在sp上处理的。
(3)sm:多个sp加上其它的一些资源(比如,存储资源、共享内存、寄储器等)组成一个sm。
(4)warp:GPU执行程序时的调度单位。目前CUDA的warp大小32,同在一个warp的线程,以不同数据资源执行相同指令。

6.CUDA核函数
解析:kernel函数完整的执行配置参数形式是<<<Dg, Db, Ns, S>>>,如下所示:
(1)参数Dg用于定义整个grid的维度和尺寸,即一个grid有多少个block。
(2)参数Db用于定义一个block的维度和尺寸,即一个block有多少个thread。
(3)参数Ns是一个可选参数,用于设置每个block除了静态分配的shared Memory以外,最多能动态分配的shared memory大小,单位为byte。不需要动态分配时该值为0或省略不写。
(4)参数S是一个cudaStream_t类型的可选参数,初始值为零,表示该核函数处在哪个流之中。

7.CUDA存储系统
解析:每个线程拥有独立的寄存器(register)和局部存储器(local memory);每个线程块拥有独立的共享存储器(shared memory);所有线程都可以访问全局存储器(global memory),以及只读存储器常量存储器(constant memory)和纹理存储器(texture memory)。如下所示:
(1)寄存器(register)
(2)局部存储器(local memory)
(3)共享存储器(shared memory)
eg:__shared__ 数据类型 变量名;
(4)全局存储器(global memory)
(5)常量存储器(constant memory)
eg:__constant__ 数据类型 变量名;
(6)纹理存储器(texture memory)

8.CUDA线程组织
解析:CUDA通过内置变量threadIdx.x、threadIdx.y、threadIdx.z表示当前线程所处的线程块的位置,blockIdx.x、blockIdx.y、blockIdx.z表示当前线程所处的线程块在整个网格中所处的位置,blockDim.x、blockDim.y、blockDim.z表示块的维度,gridDim.x、gridDim.y、gridDim.z表示网格的维度。对网格中的任意点(i, j)表征CUDA代码中的一个线程,该线程对应的网格中的索引,如下所示:

i = threadIdx.x+blockIdx.x*blockDim.x
j = threadIdx.y+blockIdx.y*blockDim.y

9.变量类型
解析:

(1)__device__:GPU的global memory空间,grid中所有线程可访问。
(2)__constant__:GPU的constant memory空间,grid中所有线程可访问。
(3)__shared__:GPU上的thread block空间,block中所有线程可访问。
(4)local:位于SM内,仅本thread可访问。

10.CUDA函数库
解析:
(1)Thrust:一个C++ STL实现的函数库。
(2)NVPP:NVIDIA性能原语(和Intel的MKK类似)。
(3)CuBLAS:BLAS(基本线性代数)函数库的GPU版本。
(4)cuFFT:GPU加速的快速傅里叶变换函数库。
(5)cuSparse:稀疏矩阵数据的线性代数和矩阵操作。
(6)Magma:LAPACK和BLAS函数库。
(7)GPU AI:基于GPU的路径规划和碰撞避免。
(8)CUDA Math Lib:支持C99标准的数学函数。
(9)Jacket:对.m代码可选的、基于GPU的Matlab引擎。
(10)Array Fire:类似于IPP、MKL和Eigen的矩阵、信号和图像处理库。
(11)CULA工具:线性代数库。
(12)IMSL:Fortran IMSL数值函数库的实现。
(13)NPP(NVIDIA Performance Primitives):提供了一系列图像和通用信号处理的函数,并且支持所有的CUDA平台。

11.Ubuntu 14.04安装CUDA 7.5
解析:由于无论是CentOS还是Ubuntu都预装了开源的nouveau显卡驱动(SUSE没有这种问题),如果不禁用,则CUDA驱动可能不能正确安装。处理方法,如下所示:

sudo vim /etc/modprobe.d/blacklist.conf
blacklist nouveau    # 增加一行
sudo apt-get --purge remove xserver-xorg-video-nouveau    # 把官方驱动彻底卸载
sudo apt-get --purge remove nvidia-*    # 清除之前安装的任何NVIDIA驱动
sudo service lightdm stop    # 进命令行,关闭Xserver
sudo kill all Xorg    # 杀死所有Xorg(Xorg软件包是包括显卡驱动、图形环境库等一系列软件包)

说明:gksudo nvidia-settings可以进行NVIDIA X Server Settings的设置。
(1)安装依赖类库

sudo apt-get update  
sudo apt-get upgrade  
sudo apt-get install build-essential cmake g++ gfortran git pkg-config python-dev software-properties-common wget
sudo apt-get autoremove 
sudo rm -rf /var/lib/apt/lists/*

(2)安装Nvidia驱动

lspci | grep -i nvidiasudo add-apt-repository ppa:graphics-drivers/ppa
sudo apt-get update
sudo apt-get install nvidia-352sudo shutdown -r now
cat /proc/driver/nvidia/version

(3)安装CUDA

sudo dpkg -i cuda-repo-ubuntu1404*amd64.deb
# sudo apt-get update
sudo apt-get install cudaecho 'export PATH=/usr/local/cuda/bin:$PATH' >> ~/.bashrc
echo 'export LD_LIBRARY_PATH=/usr/local/cuda/lib64:$LD_LIBRARY_PATH' >> ~/.bashrc
source ~/.bashrcnvcc -V
sudo shutdown -r now

(4)安装CUDA例子和测试

/usr/local/cuda/bin/cuda-install-samples-7.5.sh ~/cuda-samples
cd ~/cuda-samples/NVIDIA*Samples
make -j $(($(nproc) + 1))bin/x86_64/linux/release/deviceQuery

说明:至此安装完毕,就可以使用Nsight Eclipse Edition愉快地进行CUDA异构计算开发了。

12.二维数组使用

#include <iostream>
#include<cstdlib>
using namespace std;static const int ROW = 10;
static const int COL = 5;int main() {int** array = (int**)malloc(ROW*sizeof(int*));int* data = (int*)malloc(ROW*COL*sizeof(int));// initialize the datafor (int i=0; i<ROW*COL; i++) {data[i] = i;}// initialize the arrayfor (int i=0; i<ROW; i++) {array[i] = data + i*COL;}// output the arrayfor (int i=0; i<ROW; i++) for (int j=0; j<COL; j++) {cout << array[i][j] << endl;}free(array);free(data);return 0;
}

13.查看GPU信息的代码
  如果找不到#include <helper_cuda.h>,那么将$cuda-samples/NVIDIA_CUDA-7.5_Samples/common/inc添加到NVCC Compiler中的Includes中即可。
解析:
(1)#include
  #include<cstdlib>提供数据类型:size_t,wchar_t,div_t,ldiv_t,lldiv_t;提供常量:NULL,EXIT_FAILURE,EXIT_SUCCESS,RAND_MAX,MB_CUR_MAX;提供函数:atof,atoi,atol, strtod, strtof, strtols, strtol, strtoll, strtoul, strtoull, rand, srand, calloc, free, malloc, realloc, abort, atexit, exit, getenv, system, bsearch, qsort, abs, div, labs, ldiv, llabs, tlldiv, mblen, mbtowc, wctomb, mbstowcs, wcstombs。
(2)CUDART_VERSION
  CUDA Runtime API Version,在#include <cuda_runtime.h>中#define CUDART_VERSION 7050。
(3)stdin,stdout,stderr
  进程将从标准输入文件中得到输入数据,将正常输出数据输出到标准输出文件,而将错误信息送到标准错误文件中。stdin的文件描述符为0,stdout的文件描述符为1,stderr的文件描述符为2。
(4)host cudaError_t cudaSetDevice ( int device )
  设置device用于GPU扩展。
(5)cudaDeviceProp数据结构
  cudaDeviceProp数据类型针对函式cudaGetDeviceProperties定义的,cudaGetDeviceProperties函数的功能是取得支持GPU计算装置的相关属性,比如支持CUDA版本号装置的名称、内存的大小、最大的thread数目、执行单元的频率等。如下所示:

struct cudaDeviceProp {char name[256]; // 识别设备的ASCII字符串(比如,"GeForce GTX 940M")size_t totalGlobalMem; // 全局内存大小size_t sharedMemPerBlock; // 每个block内共享内存的大小int regsPerBlock; // 每个block 32位寄存器的个数int warpSize; // warp大小size_t memPitch; // 内存中允许的最大间距字节数int maxThreadsPerBlock; // 每个Block中最大的线程数是多少int maxThreadsDim[3]; // 一个块中每个维度的最大线程数int maxGridSize[3]; // 一个网格的每个维度的块数量size_t totalConstMem; // 可用恒定内存量int major; // 该设备计算能力的主要修订版号int minor; // 设备计算能力的小修订版本号int clockRate; // 时钟速率size_t textureAlignment; // 该设备对纹理对齐的要求int deviceOverlap; // 一个布尔值,表示该装置是否能够同时进行cudamemcpy()和内核执行int multiProcessorCount; // 设备上的处理器的数量int kernelExecTimeoutEnabled; // 一个布尔值,该值表示在该设备上执行的内核是否有运行时的限制int integrated; // 返回一个布尔值,表示设备是否是一个集成的GPU(即部分的芯片组、没有独立显卡等)int canMapHostMemory; // 表示设备是否可以映射到CUDA设备主机内存地址空间的布尔值int computeMode; // 一个值,该值表示该设备的计算模式:默认值,专有的,或禁止的int maxTexture1D; // 一维纹理内存最大值int maxTexture2D[2]; // 二维纹理内存最大值int maxTexture3D[3]; // 三维纹理内存最大值int maxTexture2DArray[3]; // 二维纹理阵列支持的最大尺寸int concurrentKernels; // 一个布尔值,该值表示该设备是否支持在同一上下文中同时执行多个内核
}

(6)host cudaError_t cudaDriverGetVersion ( int* driverVersion )
  返回CUDA驱动版本。
(7)host __device__ cudaError_t cudaRuntimeGetVersion ( int* runtimeVersion )
  返回CUDA运行时版本。
说明:__host__和__device__同时使用时触发编译系统生成同一函数的两个不同的版本。它支持一种常见的应用,即只需要重编译同一函数的源代码就可以生成一个在设备上运行的版本。
(8)#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
  WIN32,_WIN32,WIN64,_WIN64是Windows操作系统预定义的宏。这句话的目的是C/C++编程通过宏定义来判断操作系统的类型。

14.#include<device_launch_parameters.h>
解析:#include<device_launch_parameters.h>头文件包含了内核函数的5个变量threadIdx、blockDim、blockIdx、gridDim和wrapSize。

15.事件管理
解析:常用函数,如下所示:
(1)cudaEventCreate():事件的创建。
(2)cudaEventDestroy():事件的销毁。
(3)cudaEventRecord():记录事件。
(4)cudaEventSynchronize():事件同步。
(5)cudaEventElapsedTime():计算两事件的时间差。
  利用CUDA提供的事件管理API实现计时功能,如下所示:

float time;
cudaEventCreate(&start);
cudaEventCreate(&stop);
cudaEventRecord(start, 0);
{
// 需要计时的代码
}
cudaEventRecord(stop,0);
cudaEventElapsedTime(&time, start, stop);
cudaEventDestroy(start);
cudaEventDestroy(stop);

16.deviceQuery
解析:输出结果,如下所示:

root@ubuntu:~/cuda-samples/NVIDIA_CUDA-7.5_Samples/1_Utilities/deviceQuery# ./deviceQuery 
./deviceQuery Starting...CUDA Device Query (Runtime API) version (CUDART static linking)Detected 1 CUDA Capable device(s)Device 0: "GeForce 940M"CUDA Driver Version / Runtime Version          7.5 / 7.5CUDA Capability Major/Minor version number:    5.0Total amount of global memory:                 1024 MBytes (1073610752 bytes)( 3) Multiprocessors, (128) CUDA Cores/MP:     384 CUDA CoresGPU Max Clock rate:                            980 MHz (0.98 GHz)Memory Clock rate:                             1001 MhzMemory Bus Width:                              64-bitL2 Cache Size:                                 1048576 bytesMaximum Texture Dimension Size (x,y,z)         1D=(65536), 2D=(65536, 65536), 3D=(4096, 4096, 4096)Maximum Layered 1D Texture Size, (num) layers  1D=(16384), 2048 layersMaximum Layered 2D Texture Size, (num) layers  2D=(16384, 16384), 2048 layersTotal amount of constant memory:               65536 bytesTotal amount of shared memory per block:       49152 bytesTotal number of registers available per block: 65536Warp size:                                     32Maximum number of threads per multiprocessor:  2048Maximum number of threads per block:           1024Max dimension size of a thread block (x,y,z): (1024, 1024, 64)Max dimension size of a grid size    (x,y,z): (2147483647, 65535, 65535)Maximum memory pitch:                          2147483647 bytesTexture alignment:                             512 bytesConcurrent copy and kernel execution:          Yes with 1 copy engine(s)Run time limit on kernels:                     YesIntegrated GPU sharing Host Memory:            NoSupport host page-locked memory mapping:       YesAlignment requirement for Surfaces:            YesDevice has ECC support:                        DisabledDevice supports Unified Addressing (UVA):      YesDevice PCI Domain ID / Bus ID / location ID:   0 / 4 / 0Compute Mode:< Default (multiple host threads can use ::cudaSetDevice() with device simultaneously) >deviceQuery, CUDA Driver = CUDART, CUDA Driver Version = 7.5, CUDA Runtime Version = 7.5, NumDevs = 1, Device0 = GeForce 940M
Result = PASS

说明:3个SM,每个SM包含128个SP,总共384个SP。

17.矩阵分块乘法[15]
解析:
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

18.一维卷积
解析:卷积的物理意义就是加权叠加,常见的操作有一维卷积和二维卷积。需要说明的是,“幽灵元素"通常补0。因为全局存储器和常数存储器变量都是存储在DRAM中的,从DRAM中访问一个变量需要数百甚至数千个时钟周期,从DRAM访问变量的速度通常要比处理器完成算术操作的 速度慢很多。因此,DRAM的长延迟和有限带宽已经成为几乎所有现代处理器的性能瓶颈,通常被称为存储墙问题。为了缓解这个问题,现代处理器通常引进高速 缓存存储器(或多级高速缓存),以减少访问DRAM的次数。
(1)一维卷积
  该算法的缺点是受限于访问输入数组d_N的DRAM带宽,掩码数组d_M已经放在L1高速缓存。
(2)分块一维卷积1
  规定一个线程块处理的输出元素的集合成为"输出块”;计算不涉及幽灵元素的分块称为"中间块";输出数据最左边的分块称为左边界分块;输出数据最右边的分块称为右边界分块;涉及多个分块、被多个线程块加载的数据称为"光环元素"或者"边缘元素"。
  该算法的优点是将输入数组d_N分块后放入共享存储器,减少了输入数组d_N的DRAM带宽,掩码数组d_M已经放在L1高速缓存。(分块一维卷积1对一维卷积的改进)
(3)分块一维卷积2
  该算法的优点是充分利用了L2高速缓存,掩码数组d_M已经放在L1高速缓存。需要说明的是,最近的GPU(比如,Fermi)提供了通用L1和L2高速缓存,L1缓存是每个SM私有的,而L2缓存是所有SM共享的。这样的话,线程块中的光环元素可能存放在L2高速缓存中,我们直接利用光环元素即可,而不再需要将光环元素加载到线程块的共享存储器中。(分块一维卷积2对分块一维卷积1的改进)

19.cudaMemcpyToSymbol

解析:在device中,cudaMemcpyToSymbol进行赋值和读取(devicesharedconstant),而在host中,cudaMemcpy进行赋值和读取。需要说明的是,在函数体外声明的变量默认为__device__类型,即全局变量类型。cudaMemcpyToSymbol(d_M, h_M, MaskLen*sizeof(float));和cudaMemcpyFromSymbol(h_M, d_M,MaskLen*sizeof(float));功能相反。常量存储器中的内容通常放在L1高速缓存中,因为常量存储器变量在kernel函数执行期间不会改变,刚好与GPU不提供缓存一致性相符合(主要是为了最大化利用硬件资源,提高处理器的算术运算吞吐率等)。需要说明的是,现代CPU通常都支持处理器核心之间的缓存一致性。

20.shared memory与bank conflict
解析:
(1)什么是bank conflict?
  在实际中,shared memory被分割成32个等大小的存储体(比如,Maxwell架构),即bank(每个bank拥有每周期32bit=4byte=4char=1int=1float的宽度)。因为一个warp中有32个线程,相当于一个线程对应一个bank。(不同的设备,存储体的数目也不相同,比如设备Tesla架构为16个存储体,后面我们以32个存储体进行讲解)。
  对于计算能力1.0设备,前个half-warp和后个half-warp不存在bank conflict;对于计算能力2.0设备,前个half-warp和后个half-warp可能存在bank conflict,因为shared memory可以同时让32个bank响应请求。
(2)bank conflict发生的原因?
  理想情况下就是不同的线程访问不同的bank,可能是规则的访问,比如,线程0读写bank0,线程1读写bank1,也可能是不规则的,比如线程0读写bank1,线程1读写bank0。这种同一时刻每个bank只被最多1个线程访问的情况下不会出现bank conflict。特殊情况如果有多个线程同时访问同一个bank的同一个地址的时候也不会产生bank conflict,即broadcast。但当多个线程同时访问同一个bank不同的地址时,那么bank conflict就发生了。比如,线程0访问地址0,而线程1访问地址32(归一化后为0),由于它们在同一个bank中,所以就导致了冲突。因为bank conflict发生后,同一个bank的内存读写将被串行化,会导致程序性能大大降低。
(3)什么时候会发生bank conflict呢?
  bank conflict主要出现在global memory与shared memory数据交换,及设备函数对shared memory操作中。
(4)如何避免bank conflict呢?
  很多时候shared memory的bank conflict可以通过修改数据存储的方式来解决。

21.Thrust库
解析:Thrust是一款基于GPU CUDA的C++库,其中包含诸多并行算法和数据结构。Thrust主要通过管理系统底层的功能,比如memory access(内存获取)和memory allocation(内存分配)来实现加速,使得工程师们在GPU编程的环境下能更focus在算法的设计上。
(1)容器
  host_vector:为主机提供的向量类,并且驻留在主机内存中;device_vector:为设备提供的向量类,并且驻留在设备全局内存中。
说明:fill(),copy(),sequence()。
(2)算法
  转换(transformation);规约(reduction);前缀求和(prefix sum);再排序(reordering);排序(sorting)。
(3)迭代器
  constant_iterator;counting_iterator;transform_iterator;permutation_iterator;zip_iterator。

22.事件,流,纹理内存
解析:
(1)事件:CUDA中的事件本质上是一个GPU时间戳,两个事件的时间差就是算法执行时间。
(2)流:CUDA流表示一个GPU操作队列,可以将一个流看做是GPU上的一个任务,不同任务可以并行执行。
(3)纹理内存:专门为那些在内存访问模式中存在大量空间局部性的图形应用程序而设计的只读内存。

参考文献:
[1] Java bindings for CUDA:http://jcuda.org/
[2] CNN之Caffe配置:http://www.cnblogs.com/alfredtofu/p/3577241.html
[3] Setting up a Deep Learning Machine from Scratch:https://github.com/saiprashanths/dl-setup
[4] CUDA初学大全:http://www.cnblogs.com/yangs/archive/2012/07/28/2613269.html
[5] 有哪些优秀的CUDA开源代码?:https://www.zhihu.com/question/29036289/answer/42971562
[6] CUDA一维矩阵的加法:http://tech.it168.com/a2009/1112/807/000000807771.shtml
[7] CUDA二维矩阵加法:http://www.cnblogs.com/jugg1024/p/4349243.html
[8] NVIDIA CUDA Runtime API:http://docs.nvidia.com/cuda/cuda-runtime-api/index.html#axzz4G8M3LWlq
[9] C/C++是如何通过宏定义来判断操作系统的:http://www.myexception.cn/operating-system/1981774.html
[10] CUDA编程其实写个矩阵相乘并不是那么难:http://www.cnblogs.com/yusenwu/p/5300956.html
[11] CUDA实例矩阵乘法:http://wenku.baidu.com/link?url=XCOgGQqpPUns-cifgGm1tbfqmY-5wWTwkXHh1_i_5ZZX6vFmbFu22r67fWMpcs-GxsH9thzOjVeNCpKIjGjdx2SYhq7bW4qfIquRTM0AAW_
[12] 华科并行计算上机作业:http://wenku.baidu.com/link?url=1tWvUvW0t7BnFChxetS_Mr5_pCF_LZHQGLWxN-ArVVPccOM_VmoTx9IUD76l_rVMP-iPKWI97vn7wa5ZChz59rr4wlur3rL6k3MGB15qF4W
[13] CUDA编程:http://www.cnblogs.com/stewart/archive/2013/01/05/2846860.html
[14] NVIDIA Docker:GPU Server Application Deployment Made Easy:https://devblogs.nvidia.com/parallelforall/nvidia-docker-gpu-server-application-deployment-made-easy/
[15] CUDA矩阵乘法——利用共享存储器:http://blog.csdn.net/augusdi/article/details/12614247
[16] 华科并行计算上机作业:http://wenku.baidu.com/link?url=1tWvUvW0t7BnFChxetS_Mr5_pCF_LZHQGLWxN-ArVVPccOM_VmoTx9IUD76l_rVMP-iPKWI97vn7wa5ZChz59rr4wlur3rL6k3MGB15qF4W
[17] GPUWattch Energy Model Manual:http://www.gpgpu-sim.org/gpuwattch/
[18] 图形学领域的关键算法及源码链接:http://blog.csdn.net/u013476464/article/details/40857873
[19] 拷贝global memory,cudaMemcpyToSymbol和cudaMemcpy函数是否有区别:http://blog.csdn.net/litdaguang/article/details/45047015
[20] CUDA GPU编程如何避免bank conflict:http://www.th7.cn/Program/c/201512/719448.shtml
[21] CUDA共享内存bank conflict:http://blog.csdn.net/endlch/article/details/47043069
[22] CUDA bank conflict in shared memory:http://bbs.csdn.net/topics/390836540
[23] CUDA Programming Guide之shared memory的Bank Confict:http://blog.csdn.net/o_oxo_o/article/details/4296281
[24]Parallel_programming_week3.md:https://github.com/mebusy/notes/blob/c278e037aa8a59aa139fc722d01ed41cf978921d/dev_notes/Parallel_programming_week3.md
[25] Thrust:http://docs.nvidia.com/cuda/thrust/index.html#axzz4H6gsFZs3
[26] Thrust File List:http://thrust.github.io/doc/files.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/148357.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

微信小程序button按钮去除边框去除背景色

button边框 去除button边框 在button上添加plain“true”在css中添加button.avatar-wrapper {background: none}用于去除button背景色在css中添加button.avatar-wrapper[plain]{ border:0 }用于去除button边框

SpringMVC(二)@RequestMapping注解

我们先新建一个Module。 我们的依赖如下所示&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaL…

NXP公司K60N512+PWM控制BLDC电机

本篇文章介绍了使用NXP公司提供的塔式快速原型系统来驱动控制带霍尔传感器的无刷直流电机。文章涉及的塔式快速原型系统主要包括以下四个独立板卡&#xff1a;1.塔式系统支撑模块&#xff08;TWR-Elevator&#xff09;&#xff0c;用以连接微控制器以及周边模块&#xff1b;2.低…

Android开源 Skeleton 骨架屏 V1.3.0

目录 一、简介 二、效果图 三、引用 Skeleton 添加jitpack 仓库 添加依赖: 四、新增 “块”骨架屏 1、bind方法更改和变化&#xff1a; 2、load方法更改和变化&#xff1a; 五、关于上一个版本 一、简介 骨架屏的作用是在网络请求较慢时&#xff0c;提供基础占位&…

LabVIEW开发带式谱感测技术

LabVIEW开发带式谱感测技术 如今&#xff0c;通过无线网络传输的数据量正在迅速增加&#xff0c;并导致频谱稀缺。超过数十亿的无线设备将被连接起来&#xff0c;并需要互联网接入。因此&#xff0c;无线电频谱管理方案的效率不足以授予对所有设备的访问权限。在频谱分配中&am…

开源白板工具 Excalidraw 架构解读

本文讲解开源白板工具 Excalidraw 的架构设计。 版本 0.16.1 技术栈 Vite React TypeScript Yarn Husky。 脚手架原来是用的是 Create React App&#xff0c;但这个脚手架已经不维护了&#xff0c;一年多没发布新版本了。 目前市面上比较流行的 React 脚手架是 Vite&…

CSS学习小结

css的两种使用方式&#xff1a; ①内嵌样式表 ②导入外部样式表&#xff08;实际开发常用&#xff09;<link href"...." rel"stylesheet"/> 选择器&#xff1a; ①标签选择器&#xff1a;通过标签种类决定 ②类选择器&#xff1a;class"..…

SSRF+redis未授权漏洞复现

1.SSRF漏洞简介 SSRF&#xff08;Server-Side Request Forgery&#xff09;即服务器端请求伪造&#xff0c;是一种由攻击者构造攻击链传给服务器&#xff0c;服务器执行并发起请求造成安全问题的漏洞&#xff0c;一般用来在外网探测或攻击内网服务。当网站需要调用指定URL地址…

nodejs+vue养老人员活体鉴权服务系统elementui

系统 统计数据&#xff1a;统计报表、人员台账、机构数据、上报数据、核验报表等&#xff0c;养老人员活体鉴权服务是目前国家养老人员管理的重要环节&#xff0c;主要为以养老机构中养老人员信息为基础&#xff0c;每月进行活体鉴权识别并统计数据为养老补助等管理。前端功能&…

雷达编程实战之提高探测速度

有效帧频率作为雷达一个非常核心的指标&#xff0c;它代表了雷达探测识别的速度&#xff0c;速度越快&#xff0c;后级各项智能驾驶功能就能得到更快、更有效的判断。本篇文章首先从硬件的角度&#xff0c;提供了一种合理利用片上资源提高探测识别速度的常用方法&#xff0c;然…

vertx的学习总结6

Beyond the event bus 一、章节覆盖&#xff1a; 如何在事件总线之上公开服务 verticles和事件总线服务的异步测试 动态代理&#xff1a; MyService 接口 package porxy.test;import io.vertx.codegen.annotations.ProxyGen;ProxyGen public interface MyService {void he…

Neo4j最新安装教程(图文版)

目录 一、软件介绍 二、下载软件 1、官方下载 2、云盘下载 三、安装教程 1、首先配置Neo4j的环境变量 2、启动neo4j服务器 3、访问界面 一、软件介绍 官网地址&#xff1a;https://neo4j.com/ Neo4j是一个高性能、可扩展的图数据库管理系统。它专注于存储、查询和处理大…

1.6 计算机网络的性能

思维导图&#xff1a; 1.6.1 计算机网络的性能指标 前言&#xff1a; 我的理解&#xff1a; 这段前言主要介绍了关于计算机网络性能的两个方面的讨论。首先&#xff0c;计算机网络的性能可以通过一些重要的性能指标来衡量。但除了这些指标之外&#xff0c;还有一些非性能特征…

JAVA学习(4)-全网最详细~

&#x1f308;write in front&#x1f308; &#x1f9f8;大家好&#xff0c;我是Aileen&#x1f9f8;.希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流. &#x1f194;本文由Aileen_0v0&#x1f9f8; 原创 CSDN首发&#x1f412; 如…

Flutter开发之Package与Plugin

前言 在flutter中有包和插件两个概念&#xff0c;插件 (plugin) 是 package 的一种&#xff0c;全称是 plugin package&#xff0c;我们简称为 plugin&#xff0c;中文叫插件。包(Package)主要指对flutter相关功能的封装&#xff0c;类似于Android中的插件和iOS中的三方库。而插…

CUDA+cuDNN+TensorRT 配置避坑指南

深度学习模型加速部署的环境配置&#xff0c;需要在本地安装NVIDIA的一些工具链和软件包&#xff0c;这是一个些许繁琐的过程&#xff0c;而且一步错&#xff0c;步步错。笔者将会根据自己的经验来提供建议&#xff0c;减少踩坑几率。当然可以完全按照官方教程操作&#xff0c;…

插入排序:简单而有效的排序方法

在计算机科学中&#xff0c;排序算法是一个重要且常见的主题&#xff0c;它们用于对数据进行有序排列。插入排序&#xff08;Insertion Sort&#xff09;是其中一个简单但有效的排序算法。本文将详细解释插入排序的原理和步骤&#xff0c;并提供Java语言的实现示例。 插入排序的…

B2主题优化:WordPress文章每次访问随机增加访问量

老站长都知道&#xff0c;一个新站刚开始创建&#xff0c;内容也不多的时候&#xff0c;用户进来看到文章浏览量要么是0&#xff0c;要么是 个位数&#xff0c;非常影响体验&#xff0c;就会有一种“这个网站没人气&#xff0c;看来不行”的感觉。 即使你的内容做的很好&#x…

全志ARM926 Melis2.0系统的开发指引②

全志ARM926 Melis2.0系统的开发指引② 编写目的4. 编译工具链使用4.1.工具链通用配置4.2.模块的工具链配置4.3.简单的 makefile 5. 固件烧录工具的安装5.1.PhoenixSuit 的安装步骤5.2.检验 USB 驱动安装5.3.使用烧录软件 PhoenixSuit -全志相关工具和资源-.1 全志固件镜像修改工…

HTTP协议,请求响应

、概述 二、HTTP请求协议 三、HTTP响应协议 四、请求数据 1.简单实体参数 RequestMapping("/simpleParam")public String simpleParam(RequestParam(name "name" ,required false ) String username, Integer age){System.out.println (username "…