前言:本教程为笔者依据教程https://docs.vulkan.net.cn/spec/latest/index.html#_about进行Vulkan学习并结合自己的理解整理的笔记,供大家学习和参考。

(注意:代码仅为片段,非完整程序)

学习前提:

支持Vulkan的显卡以及驱动程序(NVIDIA,AMD,Intel)
具备C++编程经验(熟悉RAII,初始化列表)
支持C++的编译器(Visual Studio 2017+,GCC 7+)

往期回顾:
Vulkan入门教程 | 第一部分:Vulkan简介

一、概述

本教程将逐步解释如何创建一个基础的Vulkan实例,这是所有Vulkan程序的起点。Vulkan实例是应用程序与Vulkan驱动程序之间的连接桥梁,它相当于一个"会话",告诉系统"我的程序要使用Vulkan了,请为我分配相应的资源"。传统的OpenGL采用全局状态机模式,而Vulkan采用显式的对象模型。这意味着:

  • 显式控制:你必须明确告诉系统你要做什么
  • 多实例支持:同一个程序可以创建多个Vulkan实例
  • 更好的错误检测:每个操作都有明确的返回值

实例负责以下关键功能:

  • 初始化Vulkan系统 - 加载驱动和底层资源

  • 管理扩展和验证层 - 控制额外功能和调试工具

  • 查询可用硬件 - 发现系统中的物理设备(GPU)

  • 平台抽象 - 提供跨不同操作系统的一致接口

二、完整流程

1、添加头文件

#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>#include <iostream>
#include <stdexcept>
#include <cstdlib>

(1) #define GLFW_INCLUDE_VULKAN 是GLFW库的配置宏,它的核心作用是启用GLFW对Vulkan的原生支持。当定义此宏后,GLFW会在内部进行以下关键操作:

  • 自动包含Vulkan核心头文件<vulkan/vulkan.h>

  • 激活GLFW中与Vulkan相关的函数实现

  • 建立GLFW窗口系统与Vulkan之间的连接桥梁

  • 处理不同平台上Vulkan头文件的包含差异

没有这个宏定义,GLFW将无法提供Vulkan所需的窗口表面扩展,导致实例创建失败。它是连接GLFW窗口系统和Vulkan API的关键开关

(2)#include <GLFW/glfw3.h>是GLFW库的主头文件,提供跨平台的窗口创建和事件处理功能。在Vulkan开发中,它具体负责:

  • 创建和管理操作系统原生窗口

  • 处理键盘、鼠标等输入事件

  • 提供与Vulkan兼容的窗口表面

  • 封装不同操作系统的原生窗口API(Windows的Win32、macOS的Cocoa、Linux的X11/Wayland)

  • 实现glfwGetRequiredInstanceExtensions()函数,获取平台特定的Vulkan扩展

GLFW抽象了底层平台的窗口创建细节,使开发者能够用统一的API创建适用于Vulkan的渲染窗口,无需编写平台特定的代码。

(3)#include <iostream>C++标准输入输出库头文件,主要用于错误报告和控制台输出

(4)#include <stdexcept>C++标准异常处理头文件,提供标准异常类。这个头文件实现了错误处理的标准化,使代码能通过统一的异常处理机制管理Vulkan API可能返回的各种错误。

(5)#include <cstdlib>C标准库的C++封装头文件,提供程序基本控制功能

  • 定义程序退出码EXIT_SUCCESSEXIT_FAILURE

  • 当捕获到异常时,返回EXIT_FAILURE表示异常终止

  • 程序正常结束时返回EXIT_SUCCESS

  • 提供内存管理、随机数生成等基础功能

2、类封装的整体架构设计

class HelloTriangleApplication {
public:void run() {initWindow();//1、初始化阶段initVulkan();//2、资源准备阶段mainLoop();//3、运行阶段cleanup();//4、清理阶段}
private:GLFWwindow* window;//GLFW窗口指针VkInstance instance;//Vulkan实例句柄,这是我们与Vulkan驱动通信的桥梁// 其他私有成员...
};

类封装遵循RAII原则,资源获取即初始化,离开作用域自动清理,确保了资源的正确分配和释放,保证即使程序出现异常,析构函数也会被调用。

run()函数体现了一个经典的应用程序生命周期模式:初始化—>资源准备—>运行主循环—>清理资源,每个阶段都可以独立测试。

3、初始化窗口系统(GLFW)

const uint32_t WIDTH = 800;//定义窗口的宽度
const uint32_t HEIGHT = 600;//定义窗口的高度//类的私有成员函数
void initWindow() {glfwInit();//初始化GLFW库glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);//不使用OpenGLglfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);//禁用窗口大小调整//创建实际的窗口,参数分别是宽度、高度、窗口标题、显示器和共享上下文window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);
}

 这个函数只负责窗口相关的初始化,不涉及任何Vulkan代码。其中窗口大小变化涉及交换链重建等复杂概念,初学时选择禁用窗口大小调整。

4、创建Vulkan实例

//类的私有成员函数
void initVulkan() {createInstance();
}void createInstance() {// 配置应用程序信息VkApplicationInfo appInfo{};appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;appInfo.pApplicationName = "Hello Triangle";appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);appInfo.pEngineName = "No Engine";appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);appInfo.apiVersion = VK_API_VERSION_1_0;// 获取GLFW所需的Vulkan扩展uint32_t glfwExtensionCount = 0;const char** glfwExtensions;glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);// 配置实例创建信息VkInstanceCreateInfo createInfo{};createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;createInfo.pApplicationInfo = &appInfo;createInfo.enabledExtensionCount = glfwExtensionCount;createInfo.ppEnabledExtensionNames = glfwExtensions;createInfo.enabledLayerCount = 0; // 禁用验证层// 创建Vulkan实例if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {throw std::runtime_error("failed to create instance!");}
}

目前只在Vulkan初始化函数initVulkan()中调用了createInstance(),这是Vulkan初始化的第一步,在完成的Vulkan应用中,这里还会包括物理设备选择、逻辑设备创建等步骤。createInstance() 是创建实例的核心内容,分为以下几个部分:

//第一部分:应用程序信息结构体
VkApplicationInfo appInfo{};//描述应用程序的基本信息
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;//结构体类型标识符,Vulkan的所有结构体都需要设置这个字段
appInfo.pApplicationName = "Hello Triangle";//应用程序名称,可以被驱动程序用于优化
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);//应用程序版本号,使用VK_MAKE_VERSION宏创建
appInfo.pEngineName = "No Engine";//使用的引擎名称,这里写"No Engine"表示没有使用特定引擎
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);//引擎版本号
appInfo.apiVersion = VK_API_VERSION_1_0;//应用程序期望使用的Vulkan API版本

sType是结构体类型标识符,Vulkan的所有结构体都需要设置这个字段。在Vulkan的C语言环境中,由于缺乏C++的类型系统,每个结构体都必须通过sType字段来声明自己的类型。当这个结构体稍后被传递给驱动程序时,驱动程序会首先检查这个字段,确认接收到的确实是一个ApplicationInfo结构体,然后才会按照相应的格式来解析其他字段。

为什么需要sType?

  • 类型安全:Vulkan使用C语言编写,没有C++的类型系统,sType提供运行时类型检查
  • 版本兼容性:不同版本的Vulkan可能有不同的结构体布局,sType帮助驱动程序正确解析
  • 扩展支持:未来的扩展可以通过sType识别新的结构体类型
//第二部分:实例创建信息结构体
VkInstanceCreateInfo createInfo{};//用于创建Vulkan实例的信息结构体
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;//同样需要设置结构体类型标识符
createInfo.pApplicationInfo = &appInfo;//指向前面创建的应用程序信息结构体

这个阶段开始构建实例创建的主控制结构。VkInstanceCreateInfo是整个创建过程的核心数据结构,它将收集所有必要的信息,然后一次性传递给实例创建函数。

createInfo.pApplicationInfo = &appInfo;这行代码建立了创建信息与应用程序信息之间的引用关系。通过指针传递而不是值拷贝,避免了大量数据的复制开销。当稍后调用vkCreateInstance时,驱动程序会通过这个指针访问应用程序信息。pApplicationInfo指针的作用:

  • 信息传递:将应用程序信息传递给实例创建过程
  • 内存效率:避免复制大量数据,使用指针引用
  • 可选性:pApplicationInfo可以为nullptr,但提供信息有助于优化
//第三部分:GLFW扩展配置
uint32_t glfwExtensionCount = 0;
const char** glfwExtensions;
glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);//GLFW告诉我们需要哪些Vulkan扩展才能与窗口系统交互
createInfo.enabledExtensionCount = glfwExtensionCount;//指定要启用的扩展数量
createInfo.ppEnabledExtensionNames = glfwExtensions;//指定要启用的扩展名称列表

前三行代码执行了一个需求查询过程。GLFW作为窗口管理库,了解当前平台需要哪些Vulkan扩展才能实现窗口与Vulkan的集成。glfwGetRequiredInstanceExtensions函数的执行过程是这样的:GLFW内部会检测当前的操作系统和窗口系统,然后返回相应的扩展名称列表。在Windows上,它可能返回VK_KHR_surface和VK_KHR_win32_surface;在Linux上,可能返回VK_KHR_surface和VK_KHR_xlib_surface。

GLFW需要的典型扩展:

  • VK_KHR_surface:跨平台窗口表面抽象
  • VK_KHR_win32_surface(Windows)或VK_KHR_xlib_surface(Linux):平台特定的表面扩展

后两行代码将GLFW提供的扩展需求注册到创建信息中。enabledExtensionCount告诉驱动程序有多少个扩展需要启用,ppEnabledExtensionNames提供了扩展名称的字符串数组。

当驱动程序稍后处理创建请求时,会逐一检查这些扩展是否可用,如果任何一个扩展不存在或不兼容,整个创建过程就会失败。

//第四部分:验证层配置
createInfo.enabledLayerCount = 0;//设置为0表示不启用任何验证层,适用于发布版本

这行代码明确设置不启用任何验证层。验证层是Vulkan提供的调试和开发辅助工具,它们会拦截API调用进行额外的检查和验证。将计数设置为0表示这是一个发布版本的配置,追求最佳性能而不是调试便利性。下一篇会详细介绍验证层,验证层的拦截机制为:

应用程序调用 → 验证层 → 驱动程序
     ↑                ↓
   返回结果        检查参数/状态

//第五部分:创建实例
if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {throw std::runtime_error("failed to create instance!");//如果不等于VK_SUCCESS,说明创建失败,抛出异常
}

 这段代码执行了整个过程的核心系统调用。vkCreateInstance函数接收三个参数:

第一个参数&createInfo将前面精心准备的所有配置信息传递给驱动程序。驱动程序会详细检查这个结构体中的每一个字段,验证应用程序的需求是否可以满足。

第二个参数nullptr表示使用默认的内存分配器。Vulkan允许应用程序提供自定义的内存分配策略,但在这个简单示例中使用系统默认的分配器。

第三个参数&instance是一个输出参数,成功创建后,新实例的句柄会被写入这个变量中。

函数调用完成后,代码立即检查返回值可能的返回值及含义:

  • VK_SUCCESS:创建成功
  • VK_ERROR_OUT_OF_HOST_MEMORY:主机内存不足
  • VK_ERROR_OUT_OF_DEVICE_MEMORY:设备内存不足
  • VK_ERROR_INITIALIZATION_FAILED:初始化失败
  • VK_ERROR_LAYER_NOT_PRESENT:请求的验证层不可用
  • VK_ERROR_EXTENSION_NOT_PRESENT:请求的扩展不可用
  • VK_ERROR_INCOMPATIBLE_DRIVER:驱动程序不兼容

5、主循环

void mainLoop() {while (!glfwWindowShouldClose(window)) {//检查窗口是否应该关闭glfwPollEvents();//处理窗口事件(如键盘、鼠标输入)}
}

 标准的GLFW事件循环。

6、资源清理

void cleanup() {vkDestroyInstance(instance, nullptr);//销毁Vulkan实例,释放相关资源glfwDestroyWindow(window);//销毁GLFW窗口glfwTerminate();//终止GLFW库
}

 7、主函数和异常处理

int main() {HelloTriangleApplication app;//对象创建//如果运行过程中抛出任何继承自std::exception的异常,程序会捕获并处理try {app.run();//应用程序的主要执行函数} catch (const std::exception& e) {std::cerr << e.what() << std::endl;//错误信息输出到标准错误流return EXIT_FAILURE;}return EXIT_SUCCESS;
}

使用异常处理机制,确保程序能够优雅地处理错误,如果出现异常,打印错误信息并返回失败状态。

总结

vvkCreateInstance成功返回后,instance变量中就包含了一个有效的Vulkan实例句柄。这个句柄实际上是一个指向复杂内部结构的指针,该结构包含了:

  • 所有启用扩展的函数指针表
  • 应用程序信息的副本
  • 平台特定的窗口系统集成代码
  • 内存分配器的配置信息
  • 错误处理和调试回调的设置

此时,应用程序就获得了访问Vulkan功能的基础凭证,可以进行后续的物理设备枚举、逻辑设备创建等操作。实例的生命周期将贯穿整个应用程序运行期间,直到程序退出时在cleanup()函数中被销毁。

这整个创建过程体现了Vulkan先配置后执行的设计哲学:应用程序需要详细描述自己的需求和配置,然后系统根据这些描述一次性完成所有初始化工作,避免了运行时的不确定性和性能开销。

该部分的完整代码如下:
(1)无注释版:

#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>#include <iostream>
#include <stdexcept>
#include <cstdlib>const uint32_t WIDTH = 800;
const uint32_t HEIGHT = 600;class HelloTriangleApplication {
public:void run() {initWindow();initVulkan();mainLoop();cleanup();}private:GLFWwindow* window;VkInstance instance;void initWindow() {glfwInit();glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);}void initVulkan() {createInstance();}void mainLoop() {while (!glfwWindowShouldClose(window)) {glfwPollEvents();}}void cleanup() {vkDestroyInstance(instance, nullptr);glfwDestroyWindow(window);glfwTerminate();}void createInstance() {VkApplicationInfo appInfo{};appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;appInfo.pApplicationName = "Hello Triangle";appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);appInfo.pEngineName = "No Engine";appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);appInfo.apiVersion = VK_API_VERSION_1_0;VkInstanceCreateInfo createInfo{};createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;createInfo.pApplicationInfo = &appInfo;uint32_t glfwExtensionCount = 0;const char** glfwExtensions;glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);createInfo.enabledExtensionCount = glfwExtensionCount;createInfo.ppEnabledExtensionNames = glfwExtensions;createInfo.enabledLayerCount = 0;if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {throw std::runtime_error("failed to create instance!");}}
};int main() {HelloTriangleApplication app;try {app.run();} catch (const std::exception& e) {std::cerr << e.what() << std::endl;return EXIT_FAILURE;}return EXIT_SUCCESS;
}

(2)详细注释版:

// 定义GLFW_INCLUDE_VULKAN宏,让GLFW自动包含Vulkan头文件
// 这样我们就不需要单独包含vulkan.h了
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>// 标准C++库头文件
#include <iostream>    // 用于输出错误信息
#include <stdexcept>   // 用于异常处理
#include <cstdlib>     // 用于EXIT_SUCCESS和EXIT_FAILURE常量// 定义窗口的宽度和高度常量
const uint32_t WIDTH = 800;
const uint32_t HEIGHT = 600;class HelloTriangleApplication {
public:// 主运行函数,按顺序执行初始化、主循环和清理void run() {initWindow();    // 初始化GLFW窗口initVulkan();    // 初始化Vulkan相关资源mainLoop();      // 进入主事件循环cleanup();       // 清理所有资源}private:GLFWwindow* window;    // GLFW窗口指针VkInstance instance;   // Vulkan实例句柄,这是使用Vulkan API的入口点// 初始化GLFW窗口void initWindow() {// 初始化GLFW库glfwInit();// 设置窗口提示:不使用任何图形API(因为我们要使用Vulkan)glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);// 设置窗口提示:禁止窗口大小调整(简化示例代码)glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);// 创建窗口:宽度、高度、标题、监视器(nullptr表示窗口模式)、共享窗口(nullptr表示不共享)window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);}// 初始化Vulkan相关资源void initVulkan() {createInstance();    // 创建Vulkan实例}// 主事件循环void mainLoop() {// 持续运行直到用户关闭窗口while (!glfwWindowShouldClose(window)) {glfwPollEvents();    // 处理窗口事件(如键盘、鼠标输入)}}// 清理所有资源void cleanup() {// 销毁Vulkan实例(必须在glfwTerminate之前调用)vkDestroyInstance(instance, nullptr);// 销毁GLFW窗口glfwDestroyWindow(window);// 终止GLFW库glfwTerminate();}// 创建Vulkan实例的核心函数void createInstance() {// 步骤1:填充应用程序信息结构体VkApplicationInfo appInfo{};    // {}初始化所有成员为零// 指定结构体类型(Vulkan中每个结构体都需要指定类型)appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;// 应用程序名称(可选,但有助于驱动程序优化)appInfo.pApplicationName = "Hello Triangle";// 应用程序版本(使用VK_MAKE_VERSION宏创建版本号:主版本.次版本.补丁版本)appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);// 引擎名称(如果使用游戏引擎的话)appInfo.pEngineName = "No Engine";// 引擎版本appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);// 要使用的Vulkan API版本appInfo.apiVersion = VK_API_VERSION_1_0;// 步骤2:填充实例创建信息结构体VkInstanceCreateInfo createInfo{};// 指定结构体类型createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;// 指向应用程序信息的指针createInfo.pApplicationInfo = &appInfo;// 步骤3:获取GLFW需要的Vulkan扩展uint32_t glfwExtensionCount = 0;    // 扩展数量const char** glfwExtensions;        // 扩展名称数组// GLFW告诉我们它需要哪些Vulkan扩展来创建窗口表面glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);// 将GLFW需要的扩展添加到实例创建信息中createInfo.enabledExtensionCount = glfwExtensionCount;      // 扩展数量createInfo.ppEnabledExtensionNames = glfwExtensions;        // 扩展名称数组// 步骤4:验证层设置(这里暂时设为0,不启用任何验证层)createInfo.enabledLayerCount = 0;// 步骤5:创建Vulkan实例// 参数:创建信息、自定义分配器(nullptr使用默认)、实例句柄的指针if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {// 如果创建失败,抛出运行时异常throw std::runtime_error("failed to create instance!");}}
};// 主函数
int main() {HelloTriangleApplication app;    // 创建应用程序对象try {app.run();    // 运行应用程序} catch (const std::exception& e) {    // 捕获异常std::cerr << e.what() << std::endl;    // 输出错误信息return EXIT_FAILURE;    // 返回失败状态码}return EXIT_SUCCESS;    // 返回成功状态码
}


 欢迎学习和交流,欢迎指正!🌹🌹 

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

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

相关文章

PHP云原生架构:容器化、Kubernetes与Serverless实践

引言 随着云计算的普及,PHP应用也在向云原生架构演进。本文将深入探讨PHP在云原生环境中的最佳实践,包括容器化部署、Kubernetes编排、Serverless架构以及云原生监控与日志方案,帮助开发者构建现代化、可扩展的PHP应用。 容器化PHP应用 基础Dockerfile优化 # 多阶段构建…

【华为机试】5. 最长回文子串

文章目录5. 最长回文子串描述示例 1示例 2示例 3示例 4提示解题思路方法一&#xff1a;中心扩展法&#xff08;推荐&#xff09;方法二&#xff1a;动态规划方法三&#xff1a;Manacher算法方法四&#xff1a;暴力解法代码实现复杂度分析测试用例完整题解代码5. 最长回文子串 …

【图像处理基石】如何对遥感图像进行实例分割?

遥感图像实例分割是指在遥感影像中&#xff0c;不仅要识别出不同类别的目标&#xff08;如建筑物、车辆、道路等&#xff09;&#xff0c;还要区分同一类别中的不同个体&#xff08;如建筑物1、建筑物2&#xff09;&#xff0c;并为每个实例生成精确的像素级掩码。 一、遥感图…

电子电气架构 --- 软件bug的管理模式

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 简单,单纯,喜欢独处,独来独往,不易合同频过着接地气的生活,除了生存温饱问题之外,没有什么过多的欲望,表面看起来很高冷,内心热情,如果你身…

【每日一错】Oracle 19c CDB中如何启动一个PDB

文章目录题目扩展学习CDB与PDB的概念CDB&#xff0c;PDB结构优势总结题目 扩展学习 CDB与PDB的概念 在Oracle 12c及以上版本&#xff0c;Oracle引入了多租户架构&#xff0c;这种架构让数据库的管理和资源使用更加高效。它由两种主要组成部分组成&#xff1a; CDB&#xff0…

Android studio自带的Android模拟器都是x86架构的吗,需要把arm架构的app翻译成x86指令?

Android studio自带的Android模拟器都是x86架构的吗&#xff0c;需要把arm架构的app翻译成x86指令&#xff1f; deepseek回答&#xff1a; Android Studio 自带的官方模拟器&#xff08;Android Emulator&#xff09;主要提供基于 x86 架构的系统镜像。当运行 ARM 架构的应用…

Deep Learning_ Foundations and Concepts-Springer (2024)【拜读】20章3节

Diffusion Models 扩散模型 我们已经了解到&#xff0c;构建强大的生成模型的一种有效方法是&#xff1a;先引入一个关于潜在变量z的分布p(z)&#xff0c;然后使用深度神经网络将z变换到数据空间x。由于神经网络具有通用性&#xff0c;能够将简单固定的分布转化为关于x的高度灵…

Arduino与STM32:初学者该如何选择?

在电子爱好者和初学者的世界里&#xff0c;Arduino和STM32是两个经常被提及的名字。它们各自具有独特的优势和特点&#xff0c;适合不同类型的项目和需求。对于初学者来说&#xff0c;选择Arduino还是STM32&#xff0c;往往取决于个人的学习目标、项目需求以及预算。本文将详细…

创建型设计模式-工厂方法模式和抽象工厂方法模式

1、工厂方法模式 创建型设计模式之一 UML类图2、抽象工厂模式 也是创建型设计模式之一。虽然抽象工厂方法模式的类繁多&#xff0c;但是&#xff0c;主要分为4类。 AbstractFactory&#xff1a;抽象工厂角色&#xff0c;它声明了一组用于创建一种产品的方法&#xff0c;每一个方…

Hyperchain安全与隐私机制详解

一、核心安全机制1. 共识算法安全RBFT共识算法&#xff1a;改进型PBFT&#xff1a;基于PBFT算法优化&#xff0c;增加动态节点管理、失效数据恢复机制&#xff0c;提升系统容错性与可用性。性能指标&#xff1a;吞吐量稳定达3000-10000 TPS&#xff0c;交易执行时间控制在300ms…

Oracle优化学习十六

反连接反连接&#xff08;Anti Join&#xff09;是一种特殊的连接类型&#xff0c;与内连接和外连接不同&#xff0c;Oracle数据库里并没有相关的 关键字可以在SQL文本中专门表示反连接&#xff0c;所以这里把它单独拿出来说明。为了方便说明反连接的含义&#xff0c;我们用“t…

梳理一些 Docker 常用命令

以下是一些 Docker 常用命令&#xff0c;适用于日常开发、调试、部署等场景&#xff0c;分为几个常用类别&#xff1a;&#x1f4e6; 一、镜像&#xff08;Image&#xff09;相关命令命令说明docker images查看本地所有镜像docker pull <image>拉取镜像&#xff08;如 do…

C#_ArrayList动态数组

目录 ArrayList的特点 ArrayList 与普通数组的区别 使用示例&#xff1a; 普通数组 动态数组 主要方法和属性 属性&#xff1a; Count 获取动态数组的数据个数 读取某个位置的数据 // 索引 方法&#xff1a; Add 向集合末尾添加元素 Insert 在指定位置插入元…

Agent领域,近年来的前沿研究方向:多智能体协作、认知启发架构、伦理安全、边缘计算集成

Agent领域,近年来的前沿研究方向:多智能体协作、认知启发架构、伦理安全、边缘计算集成 在Agent领域,近年来的前沿研究方向主要集中在多智能体协作、认知启发架构、伦理安全、边缘计算集成以及生成式AI融合等方面。 一、多智能体协作与多模态任务 多智能体系统在复杂环境…

【安卓笔记】OOM与内存优化

0. 环境&#xff1a; 电脑&#xff1a;Windows10 Android Studio: 2024.3.2 编程语言: Java Gradle version&#xff1a;8.11.1 Compile Sdk Version&#xff1a;35 Java 版本&#xff1a;Java11 1.什么是OOM OOM即 OutOfMemoryError 内存溢出错误。常见于一些 资源型对…

持续集成CI与自动化测试

Python接口自动化测试零基础入门到精通&#xff08;2025最新版&#xff09;

Spring 策略模式实现

Spring 策略模式实现&#xff1a;工厂方法与自动注入详解 1. 背景介绍 在复杂的业务系统中,我们常常需要根据不同的场景选择不同的处理策略。本文将详细介绍在 Spring 框架中实现策略模式的两种主要方法。 2. 方案一: 手动注册工厂模式 2.1 定义工厂类 Component public class …

机器学习——线性回归(LinearRegression)

Python 线性回归详解&#xff1a;从原理到实战线性回归&#xff08;Linear Regression&#xff09;是机器学习中最基础也是最重要的算法之一&#xff0c;广泛应用于预测分析领域&#xff0c;例如房价预测、销售额预测等。本文将带你从理论出发&#xff0c;用 Python 手把手实现…

H.264视频的RTP有效载荷格式(翻译自:RFC6184 第5节 RTP有效载荷格式)

RTP协议格式 RFC地址&#xff1a;https://datatracker.ietf.org/doc/html/rfc6184 RTP报头的格式在RFC3550中指定 0 1 2 30 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1------------------------…

秒级构建消息驱动架构:描述事件流程,生成 Spring Cloud Stream+RabbitMQ 代码

在消息驱动架构开发中&#xff0c;Spring Cloud Stream 与 RabbitMQ 的整合往往需要手动配置绑定器、定义消息通道、编写消费逻辑&#xff0c;流程繁琐且易出错。而飞算JavaAI 作为高效的 IDE 插件&#xff0c;能让开发者通过自然语言描述事件流程&#xff0c;自动生成可运行的…