GPU异构内存管理

news2024/11/16 3:15:50

通过异构内存管理简化 GPU 应用程序开发

异构内存管理 (HMM) 是一项 CUDA 内存管理功能,它扩展了 CUDA 统一内存编程模型的简单性和生产力,以包括具有 PCIe 连接的 NVIDIA GPU 的系统上的系统分配内存。 系统分配内存是指最终由操作系统分配的内存; 例如,通过 malloc、mmap、C++ new 运算符(当然使用前面的机制)或为应用程序设置 CPU 可访问内存的相关系统例程。

以前,在基于 PCIe 的计算机上,GPU 无法直接访问系统分配的内存。 GPU 只能访问来自特殊分配器(例如 cudaMalloc 或 cudaMallocManaged)的内存。

启用 HMM 后,所有应用程序线程(GPU 或 CPU)都可以直接访问应用程序的所有系统分配内存。 与统一内存(可以被视为 HMM 的子集或前身)一样,无需在处理器之间手动复制系统分配的内存。 这是因为它会根据处理器使用情况自动放置在 CPU 或 GPU 上。

在 CUDA 驱动程序堆栈中,CPU 和 GPU 页面错误通常用于发现内存应放置在何处。 同样,这种自动放置已经在统一内存中发生 - HMM 只是扩展了行为以覆盖系统分配的内存以及 cudaMalloc 托管内存。

这种直接读取或写入完整应用程序内存地址空间的新功能将显着提高基于 CUDA 构建的所有编程模型的程序员生产力:CUDA C++、Fortran、Python 中的标准并行性、ISO C++、ISO Fortran、OpenACC、OpenMP、 以及许多其他人。

事实上,正如接下来的示例所示,HMM 简化了 GPU 编程,使得 GPU 编程几乎与 CPU 编程一样易于访问。 一些亮点:

  • 编写 GPU 程序时,功能不需要显式内存管理; 因此,最初的“初稿”计划可以小而简单。 显式内存管理(用于性能调整)可以推迟到开发的后期阶段。
  • GPU 编程现在对于不区分 CPU 和 GPU 内存的编程语言来说是实用的。
  • 大型应用程序可以通过 GPU 加速,而无需进行大量内存管理重构或更改第三方库(其源代码并不总是可用)。

顺便说一句,新的硬件平台(例如 NVIDIA Grace Hopper)通过所有 CPU 和 GPU 之间基于硬件的内存一致性来原生支持统一内存编程模型。 对于这样的系统,HMM 不是必需的,事实上,HMM 在那里被自动禁用。 思考这个问题的一种方法是观察 HMM 实际上是一种基于软件的方式,提供与 NVIDIA Grace Hopper Superchip 相同的编程模型。

HMM之前的统一内存

2013 年推出的原始 CUDA 统一内存功能使您只需进行少量更改即可加速 CPU 程序,如下所示:

CPU模式

void sortfile(FILE* fp, int N) {
  char* data;
  data = (char*)malloc(N);

  fread(data, 1, N, fp);
  qsort(data, N, 1, cmp);


  use_data(data);
  free(data);
}

原来的统一内存调用方法

void sortfile(FILE* fp, int N) {
  char* data;
  cudaMallocManaged(&data, N);

  fread(data, 1, N, fp);
  qsort<<<...>>>(data, N, 1, cmp);
  cudaDeviceSynchronize();

  use_data(data);
  cudaFree(data);
}

这种编程模型简单、清晰且功能强大。 在过去的 10 年里,这种方法使无数应用程序能够轻松地从 GPU 加速中受益。 然而,仍然有改进的空间:注意需要一个特殊的分配器:cudaMallocManaged 和相应的 cudaFree。

如果我们可以更进一步,摆脱这些呢? 这正是 HMM 所做的。

HMM之后的统一内存

在具有 HMM 的系统上(详细信息如下),继续使用 malloc 和 free:

CPU模式

void sortfile(FILE* fp, int N) {
  char* data;
  data = (char*)malloc(N);

  fread(data, 1, N, fp);
  qsort(data, N, 1, cmp);


  use_data(data);
  free(data);
}

最新的CUDA统一内存和HMM

void sortfile(FILE* fp, int N) {
  char* data;
  data = (char*)malloc(N);

  fread(data, 1, N, fp);
  qsort<<<...>>>(data, N, 1, cmp);
  cudaDeviceSynchronize();

  use_data(data);
  free(data)
}

使用 HMM,现在两者之间的内存管理是相同的。

系统分配的内存和 CUDA 分配器

使用 CUDA 内存分配器的 GPU 应用程序在具有 HMM 的系统上“按原样”工作。 这些系统的主要区别在于,像 malloc、C++ new 或 mmap 这样的系统分配 API 现在创建可以从 GPU 线程访问的分配,而无需调用任何 CUDA API 来告诉 CUDA 这些分配的存在。 下表列出了具有 HMM 的系统上最常见的 CUDA 内存分配器之间的差异:

Memory allocators on systems with HMMPlacementMigratableAccessible from:
CPUGPURDMA
System allocated
malloc, mmap, …

First-touch
GPU or CPU
YYYY
CUDA managed
cudaMallocManaged
YYN
CUDA device-only
cudaMalloc, …
GPUNN
CUDA host-pinned
cudaMallocHost, …
CPUNY
Overview of system and CUDA memory allocators on systems with HMM

一般来说,选择更好地表达应用程序意图的分配器可以使 CUDA 提供更好的性能。 借助 HMM,这些选择就变成了性能优化,无需在首次从 GPU 访问内存之前预先完成。 HMM 使开发人员能够首先专注于并行化算法,然后在开销提高性能时执行与内存分配器相关的优化。

C++、Fortran 和 Python 的无缝 GPU 加速
HMM 使使用标准化和可移植的编程语言(例如 Python)对 NVIDIA GPU 进行编程变得更加容易,Python 不区分 CPU 和 GPU 内存,并假设所有线程都可以访问所有内存,以及 ISO Fortran 和 ISO C++ 等国际标准描述的编程语言 。

这些语言提供并发和并行设施,使实现能够自动将计算分派到 GPU 和其他设备。 例如,自 C++ 2017 以来,<algorithm> 头文件中的标准库算法接受执行策略,使实现能够并行运行它们。

从 GPU 原地对文件进行排序

例如,在 HMM 之前,对大于 CPU 内存的文件进行就地排序非常复杂,需要先对文件的较小部分进行排序,然后将它们合并为完全排序的文件。 通过HMM,应用程序可以使用mmap将磁盘上的文件映射到内存中,并直接从GPU读取和写入它。 更多详情请参见GitHub上的HMM示例代码file_before.cpp和file_after.cpp。

原来的动态分配

void sortfile(FILE* fp, int N) {
  std::vector<char> buffer;
  buffer.resize(N);
  fread(buffer.data(), 1, N, fp);
  
  // std::sort runs on the GPU:
  std::sort(std::execution::par,
    buffer.begin(), buffer.end(),
    std::greater{});
  use_data(std::span{buffer});
}

最新的统一内存+HMM的动态分配

void sortfile(int fd, int N) {
  auto buffer = (char*)mmap(NULL, N, 
     PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

    
  // std::sort runs on the GPU: 
  std::sort(std::execution::par,
    buffer, buffer + N,
    std::greater{});
  use_data(std::span{buffer});
}

使用 -stdpar=gpu 选项时,并行 std::sort 算法的 NVIDIA C++ 编译器 (NVC++) 实现会对 GPU 上的文件进行排序。 该选项的使用有很多限制,HPC SDK 文档中有详细说明。

在 HMM 之前:GPU 只能访问 NVC++ 编译的代码中堆上动态分配的内存。 也就是说,CPU 线程堆栈上的自动变量、全局变量和内存映射文件无法从 GPU 访问(请参见下面的示例)。
HMM之后:GPU可以访问所有系统分配的内存,包括其他编译器和第三方库编译的CPU代码中动态分配在堆上的数据、CPU线程堆栈上的自动变量、CPU内存中的全局变量、内存映射文件等

原子内存操作和同步原语

HMM 支持所有内存操作,其中包括原子内存操作。 也就是说,程序员可以使用原子内存操作来将 GPU 和 CPU 线程与标志同步。 虽然 C++ std::atomic API 的某些部分使用 GPU 上尚不可用的系统调用(例如 std::atomic::wait 和 std::atomic::notify_all/_one API),但大多数 C++ 并发原语 API 可轻松用于在 GPU 和 CPU 线程之间执行消息传递。

有关更多信息,请参阅 GitHub 上的 HPC SDK C++ 并行算法:与 C++ 标准库的互操作性文档和atomic_flag.cpp HMM 示例代码。 您可以使用 CUDA C++ 扩展此集。 有关更多详细信息,请参阅 GitHub 上的 Ticket_lock.cpp HMM 示例代码。

Before HMM CPU←→GPU message passing

void main() {
  // Variables allocated with cudaMallocManaged
  std::atomic<int>* flag;
  int* msg;
  cudaMallocManaged(&flag, sizeof(std::atomic<int>));
  cudaMallocManaged(&msg, sizeof(int));
  new (flag) std::atomic<int>(0);
  *msg = 0;
 
  // Start a different CPU thread…
  auto t = std::jthread([&] { 
    // … that launches and waits 
    // on a GPU kernel completing
    std::for_each_n(
      std::execution::par, 
      &msg, 1, [&](int& msg) {
        // GPU thread writes message…
        *msg = 42;       // all accesses via ptrs
        // …and signals completion…
        flag->store(1);  // all accesses via ptrs
    });
  });

After HMM CPU←→GPU message passing

void main() {
  // Variables on CPU thread stack:
  std::atomic<int> flag = 0;  // Atomic
  int msg = 0;                // Message
 
  


// Start a different CPU thread…
  auto t = std::jthread([&] { 
    // … that launches and waits 
    // on a GPU kernel completing
    std::for_each_n(
      std::execution::par, 
      &msg, 1, [&](int& msg) {
        // GPU thread writes message…
        msg = 42;
        // …and signals completion…
        flag.store(1);  
    });
  });
 
  // CPU thread waits on GPU thread
  while (flag.load() == 0);
  // …and reads the message:
  std::cout << msg << std::endl;
  // …the GPU kernel and thread
  // may still be running here…
}

Before HMM CPU←→GPU locks

void main() {
  // Variables allocated with cudaMallocManaged
  ticket_lock* lock;    // Lock
  int* msg;         // Message
  cudaMallocManaged(&lock, sizeof(ticket_lock));
  cudaMallocManaged(&msg, sizeof(int));
  new (lock) ticket_lock();
  *msg = 0;

  // Start a different CPU thread…
  auto t = std::jthread([&] {
    // … that launches and waits 
    // on a GPU kernel completing
    std::for_each_n(
      std::execution::par, 
      &msg, 1, [&](int& msg) {
        // GPU thread takes lock…
        auto g = lock->guard();
        // … and sets message (no atomics)
        msg += 1;
    }); // GPU thread releases lock here
  });
  
  { // Concurrently with GPU thread
    // … CPU thread takes lock…
    auto g = lock->guard();
    // … and sets message (no atomics)
    msg += 1;
  } // CPU thread releases lock here

  t.join();  // Wait on GPU kernel completion
  std::cout << msg << std::endl;
}

After HMM CPU←→GPU locks

void main() {
  // Variables on CPU thread stack:
  ticket_lock lock;    // Lock
  int msg = 0;         // Message

  // Start a different CPU thread…
  auto t = std::jthread([&] {
    // … that launches and waits 
    // on a GPU kernel completing
    std::for_each_n(
      std::execution::par, 
      &msg, 1, [&](int& msg) {
        // GPU thread takes lock…
        auto g = lock.guard();
        // … and sets message (no atomics)
        msg += 1;
    }); // GPU thread releases lock here
  });
  
  { // Concurrently with GPU thread
    // … CPU thread takes lock…
    auto g = lock.guard();
    // … and sets message (no atomics)
    msg += 1;
  } // CPU thread releases lock here

  t.join();  // Wait on GPU kernel completion
  std::cout << msg << std::endl;
}

使用 HMM 加速复杂的 HPC 工作负载

研究大型且寿命长的 HPC 应用程序的研究小组多年来一直渴望为异构平台提供更高效、更可移植的编程模型。 m-AIA 是一款多物理场求解器,由德国亚琛工业大学空气动力学研究所开发,包含近 300,000 行代码。 有关更多信息,请参阅使用 OpenACC 加速 C++ CFD 代码。 最初的原型不再使用 OpenACC,而是使用上述 ISO C++ 编程模型在 GPU 上进行部分加速,而原型工作完成时该模型尚不可用。

HMM 使我们的团队能够加速新的 m-AIA 工作负载,这些工作负载与 GPU 无关的第三方库(例如 FFTW 和 pnetcdf)接口,这些库用于初始条件和 I/O,并且不关心 GPU 直接访问相同的内存。

利用内存映射 I/O 进行快速开发

HMM 提供的一项有趣功能是直接来自 GPU 的内存映射文件 I/O。 它使开发人员能够直接从支持的存储或/磁盘读取文件,而无需将文件暂存在系统内存中,也无需将数据复制到高带宽 GPU 内存。 这还使应用程序开发人员能够轻松处理大于可用物理系统内存的输入数据,而无需构建迭代数据摄取和计算工作流程。

为了演示此功能,我们的团队编写了一个示例应用程序,该应用程序根据 ERA5 再分析数据集构建一年中每一天的每小时总降水量直方图。 有关更多详细信息,请参阅 ERA5 全局重新分析。

ERA5 数据集由几个大气变量的每小时估计值组成。 在数据集中,每个月的总降水量数据存储在单独的文件中。 我们使用了 1981 年至 2020 年 40 年的总降水量数据,总计 480 个输入文件,总输入数据大小约为 1.3 TB。 结果示例请参见下图。

使用 Unix mmap API,可以将输入文件映射到连续的虚拟地址空间。 使用 HMM,这个虚拟地址可以作为输入传递到 CUDA 内核,然后该内核可以直接访问这些值以构建一年中所有天每小时的总降水量直方图。

生成的直方图将驻留在 GPU 内存中,可用于轻松计算有趣的统计数据,例如北半球的平均月降水量。 例如,我们还计算了二月和八月的平均小时降水量。 要查看此应用程序的代码,请访问 GitHub 上的 HMM_sample_code。

Before HMM Batch and pipeline memory transfers

size_t chunk_sz = 70_gb;
std::vector<char> buffer(chunk_sz);

for (fp : files)
  for (size_t off = 0; off < N; off += chunk_sz) {
    fread(buffer.data(), 1, chunk_sz, fp);
    cudeMemcpy(dev, buffer.data(), chunk_sz, H2D);
  
    histogram<<<...>>>(dev, N, out);
    cudaDeviceSynchronize();
  }

After HMM Memory map and transfer on demand

void* buffer = mmap(NULL, alloc_size,
                    PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 
                    -1, 0);
for (fd : files)
  mmap(buffer+file_offset, fileByteSize, 
       PROT_READ, MAP_PRIVATE|MAP_FIXED, fd, 0);


histogram<<<...>>>(buffer, total_N, out);
cudaDeviceSynchronize();

启用并检测 HMM

每当 CUDA 工具包和驱动程序检测到您的系统可以处理它时,它就会自动启用 HMM。 这些要求详细记录在 CUDA 12.2 发行说明:通用 CUDA 中。 你需要:

  • 带有开源 r535_00 驱动程序或更高版本的 NVIDIA CUDA 12.2。 有关详细信息,请参阅 NVIDIA Open GPU 内核模块安装文档。
  • 足够新的 Linux 内核:6.1.24+、6.2.11+ 或 6.3+。
  • 具有以下受支持架构之一的 GPU:NVIDIA Turing、NVIDIA Ampere、NVIDIA Ada Lovelace、NVIDIA Hopper 或更新版本。
  • 64 位 x86 CPU。

查询寻址模式属性以验证 HMM 是否已启用:

$ nvidia-smi -q | grep Addressing
Addressing Mode : HMM

要检测 GPU 可以访问系统分配的内存的系统,请查询 cudaDevAttrPageableMemoryAccess

此外,NVIDIA Grace Hopper Superchip 等系统支持 ATS,其行为与 HMM 类似。 事实上,HMM 和 ATS 系统的编程模型是相同的,因此对于大多数程序来说,仅检查 cudaDevAttrPageableMemoryAccess 就足够了。

然而,对于性能调整和其他高级编程,还可以通过查询 cudaDevAttrPageableMemoryAccessUsesHostPageTables 来区分 HMM 和 ATS。 下表显示了如何解释结果。

AttributeHMMATS
cudaDevAttrPageableMemoryAccess11
cudaDevAttrPageableMemoryAccessUsesHostPageTables01

对于只对查询 HMM 或 ATS 公开的编程模型是否可用感兴趣的可移植应用程序,查询“可分页内存访问”属性通常就足够了。

统一内存性能提示

预先存在的统一内存性能提示的语义没有变化。 对于已经在 NVIDIA Grace Hopper 等硬件一致性系统上使用 CUDA 统一内存的应用程序,主要的变化是 HMM 使它们能够在上述限制内“按原样”在更多系统上运行。

预先存在的统一内存提示也适用于 HMM 系统上的系统分配内存:

  1. __host__ cudaError_t cudaMemPrefetchAsync(* ptr, size_t nbytes, int device):
    异步将内存预取到 GPU(GPU 设备 ID)或 CPU(cudaCpuDeviceId)。
  2. __host__ cudaError_tcudaMemAdvise(*ptr, size_t nbytes, cudaMemoryAdvise,advice, int device): 提示系统:
  • 内存的首选位置:
    cudaMemAdviseSetPreferredLocation,或
  • 将访问内存的设备:cudaMemAdviseSetAccessedBy,或
  • 主要读取不经常修改的内存的设备:
    cudaMemAdviseSetReadMostly

更高级一点:有一个新的 CUDA 12.2 API cudaMemAdvise_v2,它使应用程序能够选择给定内存范围应该首选哪个 NUMA 节点。 当 HMM 将内存内容放在 CPU 端时,这一点就会发挥作用。

与往常一样,内存管理提示可能会提高或降低性能。 行为取决于应用程序和工作负载,但任何提示都不会影响应用程序的正确性。

CUDA 12.2 中 HMM 的局限性

CUDA 12.2 中的初始 HMM 实现提供了新功能,而不会降低任何现有应用程序的性能。 CUDA 12.2 中 HMM 的限制详细记录在 CUDA 12.2 发行说明:通用 CUDA 中。 主要限制是:

  • HMM仅适用于x86_64,尚不支持其他CPU架构。
  • 不支持 HugeTLB 分配上的 HMM。
  • 不支持文件支持内存和 HugeTLBfs 内存上的 GPU 原子操作。
  • 不完全支持没有后续 exec(3) 的 fork(2)。
  • 页面迁移以 4 KB 页面大小的块进行处理。

请继续关注未来的 CUDA 驱动程序更新,这些更新将解决 HMM 限制并提高性能。

总结

HMM 通过消除对在常见的基于 PCIe(通常是 x86)计算机上运行的 GPU 程序的显式内存管理的需要,简化了编程模型。 程序员可以直接使用 malloc、C++ new 和 mmap 调用,就像他们在 CPU 编程中所做的那样。

HMM 通过在 CUDA 程序中安全地使用各种标准编程语言功能,进一步提高程序员的工作效率。 无需担心意外地将系统分配的内存暴露给 CUDA 内核。

HMM 可实现与新的 NVIDIA Grace Hopper Superchip 和类似机器之间的无缝过渡。 在基于 PCIe 的机器上,HMM 提供与 NVIDIA Grace Hopper Superchip 上使用的相同的简化编程模型。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深入理解MD5:Message Digest Algorithm 5

title: 深入理解MD5&#xff1a;Message Digest Algorithm 5 date: 2024/4/21 18:10:18 updated: 2024/4/21 18:10:18 tags: MD5哈希函数密码学数据完整性碰撞攻击安全性替代算法 导论 MD5的背景和历史 MD5&#xff08;Message Digest Algorithm 5&#xff09;是一种广泛使用…

Axure引用ECharts图表 解决火狐浏览器出错

Axure原型添加Echarts图表&#xff0c;没耐心看文章的可以直接下载示例 Axure中使用ECharts图表示例 1. 打开Axure新建页面 2. 页面添加元件 元件类型随意&#xff0c;矩形、动态面板、热区、图片 甚至段落都可以3. 命名元件 随意命名&#xff0c;单个页面用到多个图表时名…

dspbuilder中使用signalcompiler时报错Error during compilation: Fitter failed,如何解决?

&#x1f3c6;本文收录于「Bug调优」专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&&…

安装IntelliJ IDEA

文章目录 一、前言二、下载IDEA三、安装四、破解 一、前言 工欲善其事必先利其器&#xff0c;学习JAVA的第一步&#xff0c;首先是安装IDE&#xff0c;配置环境&#xff1b; 常用的JAVA IDE是IntelliJ IDEA和eclipse&#xff0c;我选择IntelliJ IDEA 二、下载IDEA 官网下载&…

游戏测试之常见控制技能(下)

备注&#xff1a;未经博主允许禁止转载 个人笔记&#xff08;整理不易&#xff0c;有帮助&#xff0c;收藏点赞评论&#xff0c;爱你们&#xff01;&#xff01;&#xff01;你的支持是我写作的动力&#xff09; 笔记目录&#xff1a;学习笔记目录_pytest和unittest、airtest_w…

C++11 数据结构5 队列的概念,队列的顺序存储,实现,测试

一&#xff0c;队列的概念 队列是一种特殊的受限制的线性表。 队列&#xff08;queue&#xff09;是只允许在一端进行插入操作&#xff0c;而在另一端进行删除操作的线性表。 队列是一种先进先出的t&#xff08;First In First Out&#xff09;的线性表&#xff0c;简称FIF…

数据库管理-第171期 Oracle是用这种方式确保读一致的(20240418)

数据库管理171期 2024-04-18 数据库管理-第171期 Oracle是用这种方式确保读一致的&#xff08;20240418&#xff09;1 基本概念2 用处3 注意事项总结 数据库管理-第171期 Oracle是用这种方式确保读一致的&#xff08;20240418&#xff09; 作者&#xff1a;胖头鱼的鱼缸&#x…

Redis系列之哨兵Sentinel集群搭建

在上一篇博客&#xff0c;我们已经知道怎么搭建一个redis主从复制集群&#xff0c;但是主从集群如果出现服务器宕机的情况&#xff0c;是不会自动选举master的&#xff0c;所以需要搭建更加高可用的集群模式&#xff0c;哨兵模式&#xff0c;哨兵集群会自动监控&#xff0c;如果…

深度学习发展中的继承和创新

深度学习是一步一步发展而来的&#xff0c;新的成就也是在原有的基础上&#xff0c;逐步取得突破&#xff0c;有一些东西是一点一点变化&#xff0c;突破发展而来的&#xff0c;也就是每一次小的突破和每一次小的突破累积起来&#xff0c;构成一个明显的进步。我们可以通过观察…

python 文件 成绩分析2

‘’’ 文件score.txt中存储了学生的考试信息,内容如下 小明,98,96 小刚,90,94 小红,90,94 小王,98,96 小刘,80,90 小赵,90,96 第二列是数学成绩&#xff0c;第三列是语文成绩 请写程序分析&#xff1a; 哪些同学语文成绩是相同的?哪些同学数学成绩是相同的?哪些同学语文和数…

C语言—字符指针,指针数组和数组指针详解

字符指针 在指针的类型中我们知道有一种指针类型为字符指针 char* ; int main() {char ch w;char *pc &ch;*pc w;return 0; }还有一种使用方式如下&#xff1a; int main() {const char* pstr "hello world.";//这里是把一个字符串放到pstr指针变量里了吗…

WebSocket 快速入门 - springboo聊天功能

目录 一、概述 1、HTTP&#xff08;超文本传输协议&#xff09; 2、轮询和长轮询 3、WebSocket 二、WebSocket快速使用 1、基于Java注解实现WebSocket服务器端 2、JS前端测试 三、WebSocket进阶使用 1、如何获取当前用户信息 2、 后端聊天功能实现 一、概述 HTTP…

Linux安装Docker完整教程及配置阿里云镜像源

官网文档地址 安装方法 1、查看服务器内核版本 Docker要求CentOS系统的内核版本高于3.10 uname -r #通过 uname -r 命令查看你当前的内核版本2、首先卸载已安装的Docker&#xff08;如果有&#xff09; 2.1 确保yum包更新到最新 yum update2.2 清除原有的docker&#xff0c…

生物特征识别的六大技术研究

生物特征识别技术是结合了计算机科学与光学、声学、生物传感器以及生物统计学原理&#xff0c;通过利用人体固有的生理特征&#xff08;如指纹、人脸、虹膜、掌纹、指静脉等&#xff09;和行为特征&#xff08;如笔迹、声音、步态等&#xff09;&#xff0c;来进行个人身份的鉴…

layui--table里使用switch

1. 项目需求 在layui.table上面渲染后的列表上面加一个switch开关&#xff0c;监听switch开关的动作&#xff0c;实现本列数据的状态切换&#xff01; 实现效果如下&#xff1a; 2. 实现方式 下面介绍的思路都是利用table的templet模板实现的&#xff0c;不同的在于模板代码…

F-logic DataCube3 SQL注入漏洞复现(CVE-2024-31750)

0x01 产品简介 F-logic DataCube3是一款用于光伏发电系统的紧凑型终端测量系统。 0x02 漏洞概述 F-logic DataCube3 /admin/pr_monitor/getting_index_data.php 接口处存在SQL注入漏洞,未经身份验证的攻击者可通过该漏洞获取数据库敏感信息,深入利用可控制整个web服务器。 …

JavaEE 初阶篇-深入了解 File 文件操作(实现文件搜索、非空文件夹删除)

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 File 文件概述 2.0 创建 File 类对象的方法 2.1 判断文件类型、获取文件信息的方法 2.2 创建文件、删除文件的方法 2.3 遍历文件夹的方法 3.0 文件搜索与删除 3.1…

虚拟机中的打印机,无法打印内容,打印的是白纸或英文和数字,打印不了中文

原因&#xff1a;打印机驱动设置不正确 解决方案&#xff1a; 打开打印机属性 -> 高级 -> 新驱动程序 下一页 -> Windows 更新 耐心等待&#xff0c;时间较长。 选择和打印机型号匹配的驱动&#xff0c;我选择的是&#xff1a; 虽然虚拟机和主机使用的驱动不…

《机器学习by周志华》学习笔记-线性模型-02

1、对数几率回归 1.1、背景 上一节我们考虑了线性模型的回归学习,但是想要做分类任务就需要用到上文中的广义线性模型。 当联系函数连续且充分光滑,考虑单调可微函数,令: 1.2、概念 找一个单调可谓函数,将分类任务的真实标记与线性回归模型的预测值联系起来,也叫做「…

关系型数据库的相关概念

表、记录、字段 表 一个实体集相当于一个表记录 一个实体相当于一个记录&#xff0c;在表中表表现为一行数据字段 一个字段相当于数据库表中的列 表的关联关系 一对一(一对一的表可以合并成一张表)一对多多对多 必须创建第三张表&#xff0c;该表通常称为联接表&#xff0c…