CUDA 11功能展示

CUDA 11 Features Revealed

新的NVIDIA A100 GPU基于NVIDIA安培GPU架构,实现了加速计算的最大一代飞跃。A100 GPU具有革命性的硬件功能,我们很高兴宣布CUDA11与A100结合使用。              CUDA11使您能够利用新的硬件功能来加速HPC、基因组学、5G、渲染、深度学习、数据分析、数据科学、机器人和许多更多样化的工作负载。

CUDA11包含了从平台系统软件到开始开发GPU加速应用程序所需的所有功能。本文概述了此版本中的主要软件功能:

支持NVIDIA安培GPU体系结构,包括新的NVIDIA A100 GPU,用于加速扩展和扩展AI和HPC数据中心;具有NVSwitch结构的多GPU系统,如DGX A100和HGX A100。

多实例GPU(MIG)分区功能,特别有利于云服务提供商(csp)提高GPU利用率。

新的第三代张量核加速混合精度,矩阵运算对不同数据类型,包括TF32和Bfloat16。

用于任务图、异步数据移动、细粒度同步和二级缓存驻留控制的编程和API。

CUDA库中线性代数、FFT和矩阵乘法的性能优化。

对Nsight产品系列工具的更新,这些工具用于跟踪、分析和调试CUDA应用程序。

完全支持所有主要的CPU体系结构,包括x86_64、Arm64服务器和电源体系结构。

CUDA and NVIDIA Ampere microarchitecture GPUs

NVIDIA安培GPU微体系结构采用TSMC 7nm N7制造工艺,包含更多流式多处理器(SMs)、更大更快的内存以及与第三代NVLink互连的带宽,以提供巨大的计算吞吐量。

A100的40gb(5站点)高速HBM2内存的带宽为1.6tb/sec,比V100快1.7x以上。A100上的40 MB二级缓存几乎比Tesla V100大7倍,提供了2倍以上的二级缓存读取带宽。CUDA11在A100上提供了新的专用二级缓存管理和驻留控制API。A100中的短消息包括更大更快的组合一级缓存和共享内存单元(每短消息192 KB),以提供Volta V100 GPU总容量的1.5倍。

A100配备了专用硬件单元,包括第三代张量核心、更多视频解码器(NVDEC)单元、JPEG解码器和光流加速器。所有这些都被各种CUDA库用来加速HPC和AI应用程序。

接下来的几节将讨论NVIDIA A100中引入的主要创新,以及CUDA 11如何使您能够充分利用这些功能。CUDA 11为每个人都提供了一些东西,无论您是管理集群的平台DevOps工程师还是编写GPU加速应用程序的软件开发人员。有关NVIDIA安培GPU微体系结构的更多信息,请参阅NVIDIA安培体系结构深入文章。

Multi-Instance GPU

MIG功能可以在物理上将一个A100 GPU分成多个GPU。它允许多个客户端(如vm、容器或进程)同时运行,同时在这些程序之间提供错误隔离和高级服务质量(QoS)。

Figure 1. New MIG feature in A100.

A100是第一个可以通过NVLink扩展到完整GPU的GPU,或者通过降低每个GPU实例的成本来扩展到许多用户的MIG的GPU。MIG支持多个用例来提高GPU的利用率。这可以让CSPs租用单独的GPU实例,在GPU上运行多个推理工作负载,托管多个Jupyter笔记本会话以进行模型探索,或者在组织中的多个内部用户(单租户、多用户)之间共享GPU的资源。

MIG对CUDA是透明的,现有的CUDA程序可以在MIG不变的情况下运行,以最小化编程工作量。CUDA 11使用NVIDIA管理库(NVML)或其命令行接口NVIDIA smi(NVIDIA smi MIG子命令)在Linux操作系统上启用MIG实例的配置和管理。

使用NVIDIA容器工具包和启用MIG的A100,还可以使用Docker运行GPU容器(使用从Docker 19.03开始的--gpus选项)或使用NVIDIA设备插件扩展Kubernetes容器平台。

以下命令显示了使用nvidia smi的MIG管理:

# List gpu instance profiles:

# nvidia-smi mig -i 0 –lgip

System software platform support

为了在企业数据中心中使用,NVIDIA A100引入了新的内存错误恢复功能,可以提高恢复能力,避免影响正在运行的CUDA应用程序。先前架构上不可纠正的ECC错误将影响GPU上的所有运行工作负载,需要重置GPU。

在A100上,影响仅限于遇到错误并被终止的应用程序,而其他正在运行的CUDA工作负载不受影响。GPU不再需要重置才能恢复。NVIDIA驱动程序执行动态页面黑名单以标记页面不可用,以便当前和新应用程序不访问受影响的内存区域。

当GPU复位时,作为常规GPU/VM服务窗口的一部分,A100配备了一种称为行重映射的新硬件机制,该机制用备用单元替换内存中降级的单元,并避免在物理内存地址空间中创建任何洞。

带CUDA 11的NVIDIA驱动程序现在报告与行重映射有关的各种度量,包括带内(使用NVML/NVIDIA smi)和带外(使用系统BMC)。A100包括新的带外功能,在更多可用的GPU和NVSwitch遥测,控制和改进的总线传输数据速率之间的GPU和BMC。

为了提高多GPU系统(如DGX A100和HGX A100)的弹性和高可用性,系统软件支持禁用出现故障的GPU或NVSwitch节点的功能,而不是像前几代系统那样禁用整个基板。

CUDA 11是第一个为Arm服务器添加生产支持的版本。通过将Arm的节能CPU体系结构与CUDA结合起来,Arm生态系统将从GPU加速计算中受益,适用于各种用例:从edge、云和游戏到为超级计算机供电。CUDA 11支持Marvell基于ThunderX2的高性能服务器,并与Arm和生态系统中的其他硬件和软件合作伙伴密切合作,以快速实现对GPU的支持。

Third-generation, multi-precision Tensor Cores

NVIDIA A100中的每SM四个大张量核(总共432个张量核)为所有数据类型提供了更快的矩阵乘法累加(MMA)操作:Binary、INT4、INT8、FP16、Bfloat16、TF32和FP64。              您可以通过不同的深度学习框架、CUDA C++提供的CULCAS模板抽象或CUDA库、Cuulover、CursSuror或TunSoRT来访问张量核。

CUDA C++使用张量水平矩阵(WMMA)API来获得张量核。这种便携式API抽象公开了专门的矩阵加载、矩阵乘法和累加运算以及矩阵存储操作,以有效地使用CUDA C++程序的张量核。WMMA的所有函数和数据类型都可以在nvcuda::WMMA命名空间中使用。您还可以使用mma_sync PTX指令直接访问A100(即具有计算能力compute_80及更高版本的设备)的张量核。

CUDA 11增加了对新输入数据类型格式的支持:Bfloat16、TF32和FP64。Bfloat16是一种替代的FP16格式,但精度较低,与FP32的数值范围相匹配。它的使用导致较低的带宽和存储需求,因此更高的吞吐量。BFLAT16作为一个新的CUDA C++ ++ NVBBFLAT16数据类型,通过WMMA暴露在CUAAUBF16.H中,并由各种CUDA数学库支持。

TF32是一种特殊的浮点格式,用于张量核。TF32包括8位指数(与FP32相同)、10位尾数(与FP16精度相同)和一个符号位。它是默认的数学模式,允许您在不更改模型的情况下,通过FP32获得DL训练的加速比。最后,A100为MMA操作提供了双精度(FP64)支持,WMMA接口也支持MMA操作。

Figure 2. Table of supported data types, configurations, and performance for matrix operations.

Programming NVIDIA Ampere architecture GPUs

为了提高GPU的可编程性并利用NVIDIA A100 GPU的硬件计算能力,CUDA 11包含了新的API操作,用于内存管理、任务图加速、新指令和线程通信结构。下面我们来看看这些新操作,以及它们如何使您能够利用A100和NVIDIA安培微体系结构。

内存管理

最大化GPU内核性能的优化策略之一是最小化数据传输。如果内存驻留在全局内存中,则将数据读入二级缓存或共享内存的延迟可能需要几百个处理器周期。

例如,在GV100上,共享内存提供的带宽比全局内存快17倍或比L2快3倍。因此,一些具有生产者-消费者范式的算法可以观察到在内核之间的L2中持久化数据的性能优势,从而获得更高的带宽和性能。

在A100上,CUDA 11提供API操作,以留出40-MB L2缓存的一部分来持久化对全局内存的数据访问。持久化访问优先使用二级缓存的这一预留部分,而对全局内存的正常或流式访问只能在持久化访问未使用二级缓存的这一部分时使用。

二级持久性可以设置为在CUDA流或CUDA图内核节点中使用。在设置二级缓存区域时需要考虑一些因素。例如,多个CUDA内核在不同的流中并发执行,同时具有不同的访问策略窗口,共享二级备用缓存。下面的代码示例显示了为持久性预留二级缓存比率。

cudaGetDeviceProperties( &prop, device_id);

// Set aside 50% of L2 cache for persisting accesses

size_t size = min( int(prop.l2CacheSize * 0.50) , prop.persistingL2CacheMaxSize );

cudaDeviceSetLimit( cudaLimitPersistingL2CacheSize, size);

// Stream level attributes data structure

cudaStreamAttrValue attr ;​

attr.accessPolicyWindow.base_ptr = /* beginning of range in global memory */ ;​

attr.accessPolicyWindow.num_bytes = /* number of bytes in range */ ;​

// hitRatio causes the hardware to select the memory window to designate as persistent in the area set-aside in L2

attr.accessPolicyWindow.hitRatio = /* Hint for cache hit ratio */

// Type of access property on cache hit

attr.accessPolicyWindow.hitProp = cudaAccessPropertyPersisting;​

// Type of access property on cache miss

attr.accessPolicyWindow.hitProp = cudaAccessPropertyStreaming;

cudaStreamSetAttribute(stream,cudaStreamAttributeAccessPolicyWindow,&attr);

虚拟内存管理API操作已经扩展,以支持对固定GPU内存的压缩,从而减少二级到DRAM的带宽。这对于深入学习训练和推理用例非常重要。使用cuMemCreate创建可共享内存句柄时,将向API操作提供分配提示。

诸如3D模板或卷积等算法的有效实现涉及内存复制和计算控制流模式,其中数据从全局内存传输到线程块的共享内存中,然后是使用该共享内存的计算。全局到共享内存的拷贝被扩展成从全局内存读取到寄存器,然后写入共享内存。

CUDA 11允许您利用新的异步复制(async copy)范式。它本质上与将数据从全局复制到共享内存与计算重叠,并避免使用中间寄存器或一级缓存。异步复制的好处是:控制流不再两次遍历内存管道,并且不使用中间寄存器可以减少寄存器压力,增加内核占用率。在A100上,异步复制操作是硬件加速的。

下面的代码示例显示了一个使用异步复制的简单示例。生成的代码虽然性能更高,但可以通过多批异步复制操作的流水线进一步优化。这种额外的流水线可以消除代码中的一个同步点。              异步拷贝在CUDA 11中作为一个实验特性提供,并使用协作组集合公开。CUDA C++编程指南包括使用A级副本和多级加速流水线的AAA副本和A100中硬件加速的屏障操作的更高级示例。

//Without async-copy
 
using namespace nvcuda::experimental;
__shared__ extern int smem[];
 
// algorithm loop iteration
while ( ... ) {
 
  __syncthreads(); 
  
  // load element into shared mem
  for ( i = ... ) {
    // uses intermediate register
    // {int tmp=g[i]; smem[i]=tmp;}
    smem[i] = gldata[i]; 
  }
//With async-copy
 
using namespace nvcuda::experimental;
__shared__ extern int smem[];
 
pipeline pipe;
 
// algorithm loop iteration
while ( ... ) {
 
  __syncthreads(); 
  
  // load element into shared mem
  for ( i = ... ) {
    // initiate async memory copy
    memcpy_async(smem[i], 
                 gldata[i], 
                 pipe); 
  }
 
  // wait for async-copy to complete
  pipe.commit_and_wait();
 
  __syncthreads();
 
  /* compute on smem[] */
 
}

任务图加速

CUDA图在CUDA 10中引入,代表了一种使用CUDA提交工作的新模型。一个图由一系列操作组成,如内存拷贝和内核启动,这些操作通过依赖关系连接起来,并与执行分开定义。

任务图允许定义一次重复运行的执行流。它们可以减少累计的发射开销,并提高应用程序的总体性能。这尤其适用于深度学习应用程序,这些应用程序可能会在任务大小和运行时减少的情况下启动多个内核,或者在任务之间具有复杂的依赖关系。

从A100开始,GPU提供任务图硬件加速来预取网格启动描述符、指令和常量。与以前的gpu(如V100)相比,这改善了在A100上使用CUDA图的内核启动延迟。

CUDAGraphAPI操作现在有一个轻量级机制来支持对实例化的图的就地更新,而不需要重建图。在图的重复实例化过程中,节点参数(如内核参数)通常会在图拓扑保持不变的情况下更改。图形API操作提供了一种更新整个图形的机制,在该机制中,您可以提供具有更新的节点参数的拓扑上相同的cudaGraph_t对象,或者显式更新单个节点。

此外,CUDA图现在支持协同内核启动(cuLaunchCooperativeKernel),包括与CUDA流对等的流捕获。

线程集

下面是CUDA 11为协作组添加的一些增强,在CUDA 9中引入。协作组是一种集体编程模式,旨在使您能够显式地表示线程可以通信的粒度。这使得CUDA中出现了新的协作并行模式。

在CUDA 11中,协作组集合公开了新的A100硬件特性,并添加了一些API增强。有关完整的更改列表的更多信息,请参见CUDA C++编程指南。

A100引入了一个新的reduce指令,它对每个线程提供的数据进行操作。这是一个使用协作组的新集合,它提供了一个可移植的抽象,也可以在旧的架构上使用。reduce操作支持算术(例如add)和逻辑(例如and)操作。下面的代码示例显示了reduce集合。

// Simple Reduction Sum
#include <cooperative_groups/reduce.h>
 
   ...
   const int threadId = cta.thread_rank(); 
   int val = A[threadId]; 
   // reduce across tiled partition 
   reduceArr[threadId] = cg::reduce(tile, val, cg::plus<int>()); 
   // synchronize partition 
   cg::sync(cta); 
   // accumulate sum using a leader and return sum

协作组提供了将父组划分为一维子组的集合操作(标记为“分区”),在这些子组中,线程合并在一起。这对于试图通过条件语句的基本块跟踪活动线程的控制流特别有用。

例如,可以使用标记的分区从一个warp级别组(不受2次方的限制)中形成多个分区,并在原子添加操作中使用。labeled_partition API操作计算条件标签,并将标签值相同的线程分配到同一组中。

以下代码示例显示自定义线程分区:

// Get current active threads (that is, coalesced_threads())
cg::coalesced_group active = cg::coalesced_threads();
 
// Match threads with the same label using match_any() 
int bucket = active.match_any(value); 
 
cg::coalesced_group subgroup = cg::labeled_partition(active, bucket);
 
// Choose a leader for each partition (for example, thread_rank = 0)
// 
if (subgroup.thread_rank() == 0) { 
   threadId = atomicAdd(&addr[bucket], subgroup.size()); 
}
 
// Now use shfl to transfer the result back to all threads in partition
return (subgroup.shfl(threadId, 0));

CUDA C++ language and compiler improvements

CUDA 11也是第一个正式包含CUB作为CUDA工具包的一部分的版本。CUB现在是支持的CUDA C++核心库之一。

CUDA 11的nvcc的主要特性之一是支持链路时间优化(LTO)以提高单独编译的性能。LTO使用--dlink time opt或-dlto选项,在编译期间存储中间代码,然后在链接时执行高级优化,例如跨文件内联代码。

CUDA 11中的NVCC增加了对ISO C++ 17的支持,并支持PGI、GCC、CLAN、ARM和微软VisualStudio上的新主机编译器。如果要尝试尚未支持的主机编译器,则在编译生成工作流期间,nvcc支持一个新的--allow-unsupported-compiler标志。nvcc增加了其他新功能,包括:

改进的lambda支持

依赖项文件生成增强功能(-MD,-MMD选项)

传递选项到宿主编译器

Figure 4. Platform support in CUDA 11.  

CUDA libraries

CUDA 11中的库通过在线性代数、信号处理、基本数学运算和图像处理中常见的api之后使用最新和最强大的A100硬件特性,继续突破性能和开发人员生产力的界限。

在线性代数库中,您将看到A100上所有精度的张量核加速度,包括FP16、Bfloat16、TF32和FP64。这包括cuBLAS中的BLAS3运算、cuSOLVER中的因子分解和稠密线性解算,以及cuTENSOR中的张量收缩。

除了提高了精度范围外,还消除了张量核加速度对矩阵尺寸和对准的限制。对于适当的精度,加速度现在是自动的,不需要用户选择加入。cuBLAS的启发式算法在GPU实例上运行时自动适应资源,MIG在A100上运行。

Figure 6. Mixed-precision matrix multiply on A100 with cuBLAS.

CurLASS,CUDA C++模板的高性能GEMM抽象,支持A100提供的各种精度模式。有了CUDA11,CUTLASS现在可以实现与cuBLAS 95%以上的性能对等。这允许您编写自己的自定义CUDA内核,以便在NVIDIA GPU中编程张量内核。

cuFFT利用A100中较大的共享内存大小,从而在较大的批处理大小下为单精度fft带来更好的性能。最后,在多GPU A100系统上,袖口可伸缩,每GPU的性能是V100的两倍。

nvJPEG是一个GPU加速的JPEG解码库。与NVIDIA DALI(一个数据增强和图像加载库)一起,可以加速对图像分类模型,特别是计算机视觉的深入学习训练。图书馆加速了深度学习工作流的图像解码和数据扩充阶段。

A100包括一个5核硬件JPEG解码引擎,nvJPEG利用硬件后端对JPEG图像进行批量处理。通过专用硬件块的JPEG加速减轻了CPU上的瓶颈,并允许更好的GPU利用率。

选择硬件解码器由给定图像的nvjpeg解码自动完成,或者通过使用nvjpegCreateEx init函数显式选择硬件后端来完成。nvJPEG提供了基线JPEG解码的加速,以及各种颜色转换格式,例如YUV 420、422和444。

与仅使用CPU的处理相比,这将使图像解码速度提高18倍。如果您使用DALI,您可以直接受益于这种硬件加速,因为nvJPEG是抽象的。

Figure 9. nvJPEG Speedup vs. CPU. (Batch 128 with Intel Platinum 8168 @2GHz 3.7GHz Turbo HT on; with TurboJPEG)

CUDA数学库中的特性比一篇文章所能涵盖的要多得多。

Developer tools

CUDA 11继续在现有的开发工具组合中添加丰富的特性。这包括熟悉的Visual Studio插件、NVIDIA Nsight Integration for Visual Studio和Eclipse插件版本。它还包括独立的工具,如用于内核分析的Nsight Compute和用于系统范围性能分析的Nsight系统。Nsight Compute和Nsight系统现在在CUDA支持的所有三种CPU体系结构上都受支持:x86、POWER和Arm64。

Nsight Compute for CUDA 11的一个关键特性是能够生成应用程序的屋顶模型。屋顶模型是一种直观的方法,通过将浮点性能、算术强度和内存带宽结合到二维图中,您可以直观地了解内核特性。

通过查看屋顶线模型,可以快速确定内核是计算绑定的还是内存绑定的。您还可以了解进一步优化的潜在方向,例如,靠近屋顶线的内核可以优化使用计算资源。

有关详细信息,请参见屋顶线性能模型。

Figure 11. A Roofline model in Nsight Compute.

CUDA 11包括Compute Sanitizer,这是一个新一代的功能正确性检查工具,它提供了对越界内存访问和竞争条件的运行时检查。Compute Sanitizer是cuda memcheck工具的替代品。              下面的代码示例显示了计算清理器检查内存访问的示例。

//Out-of-bounds Array Access
__global__ void oobAccess(int* in, int* out)
{
    int bid = blockIdx.x;
    int tid = threadIdx.x;
    if (bid == 4)
    {
        out[tid] = in[dMem[tid]];
    }
}
 
int main()
{
    ...
    // Array of 8 elements, where element 4 causes the OOB
    std::array<int, Size> hMem = {0, 1, 2, 10, 4, 5, 6, 7};
    cudaMemcpy(d_mem, hMem.data(), size, cudaMemcpyHostToDevice);
 
    oobAccess<<<10, Size>>>(d_in, d_out);
    cudaDeviceSynchronize();
    ... 
$ /usr/local/cuda-11.0/Sanitizer/compute-sanitizer --destroy-on-device-error kernel --show-backtrace no basic
========= COMPUTE-SANITIZER
Device: Tesla T4
========= Invalid __global__ read of size 4 bytes
=========     at 0x480 in /tmp/CUDA11.0/ComputeSanitizer/Tests/Memcheck/basic/basic.cu:40:oobAccess(int*,int*)
=========     by thread (3,0,0) in block (4,0,0)
=========     Address 0x7f551f200028 is out of bounds

下面的代码示例显示了用于竞争条件检查的计算清理器示例。

//Contrived Race Condition Example
__global__ void Basic()
{
    __shared__ volatile int i;
    i = threadIdx.x;
}
 
int main()
{
    Basic<<<1,2>>>();
    cudaDeviceSynchronize();
    ...
$ /usr/local/cuda-11.0/Sanitizer/compute-sanitizer --destroy-on-device-error kernel --show-backtrace no --tool racecheck --racecheck-report hazard raceBasic
========= COMPUTE-SANITIZER
========= ERROR: Potential WAW hazard detected at __shared__ 0x0 in block (0,0,0) :
=========     Write Thread (0,0,0) at 0x100 in /tmp/CUDA11.0/ComputeSanitizer/Tests/Racecheck/raceBasic/raceBasic.cu:11:Basic(void)
=========     Write Thread (1,0,0) at 0x100 in /tmp/CUDA11.0/ComputeSanitizer/Tests/Racecheck/raceBasic/raceBasic.cu:11:Basic(void)
=========     Current Value : 0, Incoming Value : 1
=========
========= RACECHECK SUMMARY: 1 hazard displayed (1 error, 0 warnings)

最后,尽管CUDA11不再支持在macOS上运行应用程序,但我们正在为macOS主机上的用户提供开发工具:

  • Remote target debugging using cuda-gdb
  • NVIDIA Visual Profiler
  • Nsight Eclipse plugins
  • The Nsight family of tools for remote profiling or tracing

Summary

CUDA11提供了一个基本的开发环境,用于为NVIDIA安培GPU体系结构构建应用程序,并在NVIDIA A100上为人工智能、数据分析和HPC工作负载构建强大的服务器平台,这两个平台都用于内部部署(DGX A100)和云部署(HGX A100)。

Figure 12. Different ways to get CUDA 11.

CUDA 11即将上市。与往常一样,您可以通过多种方式获得CUDA 11:下载本地安装程序包、使用包管理器安装或从各种注册中心获取容器。对于企业部署,CUDA11还包括RHEL8的驱动程序打包改进,使用模块化流来提高稳定性和减少安装时间。

要了解有关CUDA 11的更多信息并获得问题的答案,请注册以下即将举行的在线研讨会:

另外,请注意以下有关GTC的谈话,深入探讨本帖中所涉及的A100的功能。

CUDA 11功能展示的更多相关文章

  1. CUDA 11功能清单

    CUDA 11功能清单 基于NVIDIA Ampere GPU架构的新型NVIDIA A100 GPU在加速计算方面实现了最大的飞跃.A100 GPU具有革命性的硬件功能,CUDA 11与A100一起 ...

  2. Web版记账本开发记录(一)代码和功能展示

    一丶基本机构 数据库截图 record表 年份表 index.jsp <%@ page language="java" contentType="text/html ...

  3. C#Light 再推荐,顺便介绍WP8 功能展示项目

    由于在项目中验证了C#Light脚本,C#Light的健壮和稳定程度已经得到了很大的提升. 现在可以更好的把C#Light介绍给大家使用,同时也有更多的自信,告诉大家这是一个已经具有商业价值的类库. ...

  4. "我爱记单词"测试报告兼功能展示

    "我爱记单词"测试报告兼功能展示 前言: 我们大部分的测试都是一边开发一边完成的,这里给出软件开发基本完成后在使用时的一些测试例子. 一.背景介绍 我们的数据库中一共有10个表: ...

  5. Winform开发框架之客户关系管理系统(CRM)的开发总结系列1-界面功能展示

    一直以来,都希望整合一个以客户为中心的平台,有两个方面的考虑:一是实现客户数据.客户关系.客户管理等方面的整合,以便更好利用好客户的相关资源,发挥最大的营销效益:二是整合目前我的开发框架的所有模块和技 ...

  6. Nginx功能展示实验

    Nginx功能展示实验 Nging可以作为反代服务器:也可以作为负载均衡器,并自带根据对后端服务器健康状态检测具有增删服务器的功能:也可以作为纯Web服务器,提供Web服务. 本实验将使用Nginx实 ...

  7. iOS 通知的变化ios9-10,新功能展示

    二.新功能展示 1  使用 /iOS通知新功能玩法 2.  全面   iOS10里的通知与推送详情 一.变化 四.Notification(通知) 自从Notification被引入之后,苹果就不断的 ...

  8. 这是您一直期待的所有iOS 11功能的屏幕截图

    Tips 原文作者:Chris Mills 原文地址:Here's all the iOS 11 screenshots you've been waiting for 除非你已经深陷VR其中,否则现 ...

  9. 心迹 使用说明&功能展示

    下载地址 心迹.apk 更新于2018.8.9 11:47 测试账号:用户名testing,密码testing 项目地址 GitHub 注册&登录 第一次使用心迹app时,必须进行注册,以便区 ...

随机推荐

  1. 【策略模式】策略模式结合Spring实战Demo

    策略模式 策略模式用于解决判断分支过多的问题,使代码变得简洁和优雅, 策略模式在多种方式在项目中落地,下面举例说明通过指定不同类型的订单使用策略模式执行不同的业务逻辑 文章参考自公众号:石杉的架构笔记 ...

  2. DexHunter的原理分析和使用说明(二)

    本文博客地址:http://blog.csdn.net/qq1084283172/article/details/53715325 前面的博文<Android通用脱壳工具DexHunter的原理 ...

  3. NTDDK 从两个最简单的驱动谈起

    第 1 章 从两个最简单的驱动谈起 Windows 驱动程序的编写,往往需要开发人员对 Windows 内核有深入了解和大量的内 核调试技巧,稍有不慎,就会造成系统的崩溃.因此,初次涉及 Window ...

  4. PHP解压压缩包文件到指定目录的实现

    $src_file为文件路径,上传文件返回压缩包路径即可 public function unzip($src_file, $dest_dir=false, $create_zip_name_dir= ...

  5. mysql安装_图文详细安装步骤_让你轻松安装并使用(超详细步骤)

    mysql的下载就不用说了,自行到官网下载..(本人下载的是mysql5.0版本) 下面开始正式安装 1.双击mysql_setup.exe后,直接点击Next 2.选择"I accept ...

  6. dynamic_cast和typeid

    1. C++有三个支持RTTI的元素. 如果可能的话,dynamic_cast运算符将使用一个指向基类的指针来生成一个指向派生类的指针,否则,该运算符返回0--空指针. typeid运算符返回一个对t ...

  7. uni-app 微信支付

    小程序 支付 先看官方文档 https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_8_2.shtml 知晓有那些比不可少的流程,之后后端 ...

  8. Jmeter(四十五) - 从入门到精通高级篇 - Jmeter之网页爬虫-上篇(详解教程)

    1.简介 上大学的时候,第一次听同学说网页爬虫,当时比较幼稚和懵懂,觉得就是几只电子虫子爬在网页上在抓取东西.后来又听说写代码可以实现网页爬虫,宏哥感觉高大上,后来工作又听说,有的公司做爬虫被抓的新闻 ...

  9. Envoy:经过envoy代理后获取客户端真实IP

    在envoy作为前端代理时,用户ip的获取很重要,一般获取ip的方式.都是通过Header中的 X-Forward-For. X-Real-IP或 Remote addr 等属性获取,但是如果确保En ...

  10. Mysql 数据库基本操作

    1.数据库设置密码 [root@db02 scripts]# mysqladmin -uroot password 123 2.使用密码登录 #1.正确的方式(不规范) [root@db02 scri ...