electron基础使用

安装以及运行

当前node版本18+,按照官网提供操作,npm init进行初始化操作,将index.js修改为main.js,执行npm install --save-dev electron。(这里我挂梯子下载成功了。),添加如下代码至package.json

  "scripts": {"start": "electron ."},

新建一个index.html文件,内容随意。新建一个main.js文件,内容如下。主要意思是将一个界面加载到一个应用窗口中。createWindow()方法来将index.html加载进一个新的BrowserWindow实例。在 app 模块的 ready 事件被激发后才能创建浏览器窗口。 可以通过使用 app.whenReady() API来监听此事件。 在whenReady()成功后调用createWindow()函数来打开窗口。

  • app 模块,它控制应用程序的事件生命周期。
  • BrowserWindow 模块,它创建和管理应用程序 窗口。
const { app, BrowserWindow } = require("electron");const createWindow = () => {const win = new BrowserWindow({width: 800,height: 600,});win.loadFile("index.html");
};app.whenReady().then(() => {createWindow();
});

添加关闭应用窗口事件,若输出有乱码则参考该博客输出乱码解决

app.on("window-all-closed", () => {if (process.platform !== "darwin") {console.log("关闭");app.quit();}
});

在这里插入图片描述
添加代码至BrowserWindow中,可以打开控制台操作,应用开启后可以使用ctrl+shift+i打开控制台

    webContents: {openDevTools: true,},

在这里插入图片描述

vue3中运行

基于@quick-start/electron框架快速创建一个基于vue3+electron的项目结构。

npm create @quick-start/electron

最近又新看见一个框架electron-gg地址,感觉挺好的也是基于vue3

预加载脚本

Electron 的主进程是一个拥有着完全操作系统访问权限的 Node.js 环境。 除了 Electron 模组 之外,您也可以访问 Node.js 内置模块 和所有通过 npm 安装的包。 另一方面,出于安全原因,渲染进程默认跑在网页页面上,而并非 Node.js里。

主进程负责管理整个应用程序的生命周期,包含创建窗口,运行在nodejs环境中,每次打开一个窗口,实际是创建一个渲染进程。主进程和渲染进程之间通过IPC通信。

为了将 Electron 的不同类型的进程桥接在一起,我们需要使用被称为 预加载 的特殊脚本。

BrowserWindow 的预加载脚本运行在具有 HTML DOM 和 Node.js、Electron API 的有限子集访问权限的环境中。预加载脚本默认 沙盒化不再拥有完整 Node.js 环境的访问权。 实际上,这意味着你只拥有一个 polyfilled 的 require 函数,这个函数只能访问一组有限的 API。
在这里插入图片描述
预加载脚本在渲染器加载网页之前注入。 如果你想为渲染器添加需要特殊权限的功能,可以通过 contextBridge 接口定义 全局对象。

创建preload.js文件,该脚本通过 versions 这一全局变量,将 Electron 的 process.versions 对象暴露给渲染器。

const { contextBridge } = require('electron')
contextBridge.exposeInMainWorld('versions', {node: () => process.versions.node,chrome: () => process.versions.chrome,electron: () => process.versions.electron// 除函数之外,我们也可以暴露变量
})

将脚本附在渲染进程上,在 BrowserWindow 构造器中使用 webPreferences.preload 传入脚本的路径。webPreferences对象是用来定制渲染进程中的特性,其中preload属性是在网页运行其他脚本之前执行的脚本,用来提前注入Nodejs api或者其他需要再渲染进程中运行的脚本。

const { app, BrowserWindow } = require('electron')
const path = require('node:path')const createWindow = () => {const win = new BrowserWindow({width: 800,height: 600,webPreferences: {preload: path.join(__dirname, 'preload.js')}})win.loadFile('index.html')
}app.whenReady().then(() => {createWindow()
})

现在渲染器能够全局访问 versions 了,但是还需要将版本等数据渲染到界面中,可以通过window.versions访问,也可以很简单地使用 versions 来访问。 新建一个 renderer.js 脚本, 使用 document.getElementById DOM API 来替换 id 属性为 info 的 HTML 元素的文本。

const information = document.getElementById('info')
information.innerText = `本应用正在使用 Chrome (v${versions.chrome()}), Node.js (v${versions.node()}), 和 Electron (v${versions.electron()})`

然后再index.html文件中引入

  <script src="./renderer.js"></script>

在这里插入图片描述

进程之间通信(简略)

Electron 的主进程和渲染进程有着清楚的分工并且不可互换,无论是从渲染进程直接访问 Node.js 接口,亦或者是从主进程访问 HTML 文档对象模型 (DOM),都是不可能的。
解决这一问题的方法是使用进程间通信 (IPC)。可以使用 Electron 的 ipcMain 模块 ipcRenderer 模块来进行进程间通信。 为了从你的网页向主进程发送消息,你可以使用ipcMain.handle设置一个主进程处理程序(handler),然后在预处理脚本中暴露一个被称为 ipcRenderer.invoke 的函数来触发该处理程序(handler)。

const { contextBridge, ipcRenderer } = require("electron");
contextBridge.exposeInMainWorld("versions", {node: () => process.versions.node,chrome: () => process.versions.chrome,electron: () => process.versions.electron,ping: () => ipcRenderer.invoke("ping"),
});

主进程中设置你的 handle 监听器,在 HTML 文件加载之前完成了这些,所以才能保证在你从渲染器发送 invoke 调用之前处理程序能够准备就绪。
渲染主进程中引入const { app, BrowserWindow, ipcMain } = require("electron");

app.whenReady().then(() => {ipcMain.handle("ping", () => "pong");createWindow();
});

将发送器与接收器设置完成之后,现在你可以将信息通过刚刚定义的 ‘ping’ 通道从渲染器发送至主进程当中。修改renderer中的文件

const func = async () => {const response = await window.versions.ping()console.log(response) // 打印 'pong'
}func()

在这里插入图片描述

打包程序

Electron 的核心模块中没有捆绑任何用于打包或分发文件的工具。 如果您在开发模式下完成了一个 Electron 应用,需要使用额外的工具来打包应用程序 (也称为可分发文件) 并分发给用户 。 可分发文件可以是安装程序 (例如 Windows 上的 MSI) 或者绿色软件 (例如 macOS 上的 .app 文件)。Electron Forge 是一个处理 Electron 应用程序打包与分发的一体化工具。 在工具底层,它将许多现有的 Electron 工具 (例如 @electron/packager、 @electron/osx-sign、electron-winstaller 等) 组合到一起。

安装打包工具npm install --save-dev @electron-forge/cli,然后输入npx electron-forge import等待初始化完毕,之后package会变为如下图所示
在这里插入图片描述

创建一个可分发版本

要创建可分发文件,请使用项目中的 make 脚本,该脚本最终运行了 electron-forge make 命令。npm run make注意如果npm init 的时候,author 与 description 可为任意值,但对于应用打包是必填项。如果没有则会出现如下错误
在这里插入图片描述
注意,项目打包路径中不能包含中文字符,否则报错。 打包成功如下
在这里插入图片描述

  1. npm run make它将首先运行 electron-forge package ,把您的应用程序 代码与 Electron 二进制包结合起来。
  2. 完成打包的代码将会被生成到一个特定的文件夹中。 然后它将使用这个文件夹为每个 maker 配置生成一个可分发文件。
    在这里插入图片描述
    打包完成后查看.exe文件运行。
    在这里插入图片描述

代码签名

为了将桌面应用程序分发给最终用户,我们 强烈建议 您对 Electron 应用进行 代码签名。 代码签名是交付桌面应用程序的重要组成部分,并且它对于应用程序的自动更新功能 (将会在教程最后部分讲解) 来说是必需的。

代码签名是一种可用于证明桌面应用程序是由已知来源创建的安全技术。 Windows 和 macOS 拥有其特定的代码签名系统,这将使用户难以下载或启动未签名的应用程序。代码签名在forge.config.js文件中添加

流程模型

多进程模型:在早期,浏览器通常使用单个进程来处理所有这些功能。 虽然这种模式意味着您打开每个标签页的开销较少,但也同时意味着一个网站的崩溃或无响应会影响到整个浏览器。Chrome 团队决定让每个标签页在自己的进程中渲染, 从而限制了一个网页上的有误或恶意代码可能导致的对整个应用程序造成的伤害。 然后用单个浏览器进程控制这些标签页进程,以及整个应用程序的生命周期。
在这里插入图片描述
electron包含两种进程:主进程和渲染进程。每个 Electron 应用都有一个单一的主进程,作为应用程序的入口点。 主进程在 Node.js 环境中运行,这意味着它具有 require 模块和使用所有 Node.js API 的能力。主进程的主要目的是使用 BrowserWindow 模块创建和管理应用程序窗口。BrowserWindow 类的每个实例创建一个应用程序窗口,且在单独的渲染器进程中加载一个网页。 您可从主进程用 window 的 webContent 对象与网页内容进行交互。

const { BrowserWindow, app } = require("electron");const createWindow = () => {const win = new BrowserWindow({width: 800,height: 800,});win.loadURL("https://github.com"); //网页以地址的形式引入console.log(win.webContents); //主进程中输出
};app.whenReady().then(() => {createWindow();
});

在这里插入图片描述
当一个 BrowserWindow 实例被销毁时,与其相应的渲染器进程也会被终止。

渲染进程:每个 Electron 应用都会为每个打开的 BrowserWindow ( 与每个网页嵌入 ) 生成一个单独的渲染器进程。 洽如其名,渲染器负责 渲染 网页内容。 所以实际上,运行于渲染器进程中的代码是须遵照网页标准的 (至少就目前使用的 Chromium 而言是如此) 。渲染器无权直接访问 require 或其他 Node.js API

Preload 脚本:预加载(preload)脚本包含了那些执行于渲染器进程中,且先于网页内容开始加载的代码 。 这些脚本虽运行于渲染器的环境中,却因能访问 Node.js API 而拥有了更多的权限。预加载脚本可以在 BrowserWindow 构造方法中的 webPreferences .preload选项里被附加到主进程。预加载脚本与浏览器共享同一个全局 Window 接口,并且可以访问 Node.js API,所以它通过在全局 window 中暴露任意 API 来增强渲染器,以便你的网页内容使用。

虽然预加载脚本与其所附着的渲染器在共享着一个全局 window 对象,但您并不能从中直接附加任何变动到 window 之上,因为 contextIsolation 是默认的,因此下面这段代码在窗口的控制台中输出undefined

//preload.js
window.myAPI = {desktop: true
}
//renderer.js
console.log(window.myAPI)
// => undefined

因此需要使用 contextBridge 模块来安全地实现交互.

const { contextBridge } = require('electron')
contextBridge.exposeInMainWorld('myAPI', {desktop: true
})

在这里插入图片描述

上下文隔离

上下文隔离功能将确保您的 预加载脚本 和 Electron的内部逻辑 运行在所加载的 webcontent网页 之外的另一个独立的上下文环境里。 这对安全性很重要,因为它有助于阻止网站访问 Electron 的内部组件 和 您的预加载脚本可访问的高等级权限的API

这意味着,实际上,您的预加载脚本访问的 window 对象并不是网站所能访问的对象。 例如,如果您在预加载脚本中设置 window.hello = ‘wave’ 并且启用了上下文隔离,当网站尝试访问window.hello对象时将返回 undefined。

自 Electron 12 以来,默认情况下已启用上下文隔离,并且它是 所有应用程序推荐的安全设置。

其实不使用contextBridge 创建预加载脚本就是没有开启上下文的方式。

进程通信

进程通信的表现形式例如 UI 调用原生 API 或从原生菜单触发 Web 内容的更改。

IPC通道

在 Electron 中,进程使用 ipcMainipcRenderer模块,通过开发人员定义的“通道”传递消息来进行通信。 这些通道是 任意 (您可以随意命名它们)和 双向 (您可以在两个模块中使用相同的通道名称)的。

  1. 渲染器进程到主进程(单向)
    要将单向 IPC 消息从渲染器进程发送到主进程,您可以使用 ipcRenderer.send API 发送消息,然后使用 ipcMain.on API 接收。如下是一个事例,用户输入input内容,点击按钮会修改窗口的标题
index.htmlTitle: <input id="title"/><button id="btn" type="button">Set</button><script src="./renderer.js"></script>
renderer.js
const setButton = document.getElementById('btn')
const titleInput = document.getElementById('title')
setButton.addEventListener('click', () => {const title = titleInput.valuewindow.aaa.setTitle(title) // 渲染主线程使用预加载脚本暴露的通道,使用其提供的方法
})
const { contextBridge, ipcRenderer } = require("electron");
contextBridge.exposeInMainWorld("aaa", {//aaa是自定义的通道名//定义一个setTitle函数,通过send方法向主进程发生一个set-title消息,并携带参数setTitle: (title) => ipcRenderer.send("set-title", title), //send方法是一个异步行为
});
main.js
const { BrowserWindow, app, ipcMain } = require("electron");
const path = require("path");function handleSetTitle(e, title) {/* 事件对象 e 中获取发送该事件的 webContents 对象。在 Electron 中,webContents 代表了渲染器进程内的网页内容,每个 Electron 窗口里都有一个与其关联的 webContents 实例*/const webContents = e.sender;/* BrowserWindow.fromWebContents 方法,并传入前面获得的 webContents 对象,可以获取到关联该 webContents 的 BrowserWindow 实例。基本上这行代码是根据渲染器进程(webContents)找到对应的窗口对象(BrowserWindow 实例)。*/const w = BrowserWindow.fromWebContents(webContents);w.setTitle(title);
}const createWindow = () => {const win = new BrowserWindow({width: 800,height: 800,webPreferences: {preload: path.join(__dirname, "preload.js"),},webContents: {openDevTools: true,},});win.loadFile("index.html");
};app.whenReady().then(() => {//ipcMain.on监听set-title行为,箭头从渲染器进程中使用setTitle方法发送而来的set-title消息(可以理解vue的事件监听emit)ipcMain.on("set-title", handleSetTitle);createWindow();
});

在这里插入图片描述
其中事件对象的结构如下
在这里插入图片描述

  1. 渲染器进程到主进程(双向):如下是一个事例,用户选中一个文件,显示该文件的路径。
index.html<button type="button" id="btn">Open a File</button>File path: <strong id="filePath"></strong><script src="./renderer.js"></script>
renderer.js
const btn = document.getElementById("btn");
const filePathElement = document.getElementById("filePath");btn.addEventListener("click", async () => {const filePath = await window.electronAPI.openFile();filePathElement.innerText = filePath;
});
preload.js
const { contextBridge, ipcRenderer } = require("electron/renderer");
contextBridge.exposeInMainWorld("electronAPI", {/* 异步发送一个需要响应的消息,并且等待主进程的回复。这是异步操作,但允许以类似于同步调用的方式(使用 async/await 或者基于 Promise 的方法)等待响应。*/openFile: () => ipcRenderer.invoke("dialog:openFile"),
});
const { app, BrowserWindow, ipcMain, dialog } = require("electron/main");
const path = require("node:path");async function handleFileOpen() {/* dialog 模块用于显示原生的对话框,例如文件打开、保存、消息提示等。dialog 模块是 Electron 提供的一个系统对话框接口,可以在主进程中使用,用于与用户进行交互。dialog 模块通过其 showOpenDialog 方法用于显示一个文件选择对话框。这个方法是异步的,它会返回一个 Promise。当用户选择文件并关闭对话框时,Promise 被解决(resolved),并带有一个对象,这个对象包含了两个属性:canceled 和 filePaths。canceled 是一个布尔值,表示用户是否取消了对话框而没有选择任何文件filePaths 是一个数组,包含用户选择的一个或多个文件的完整路径。*/const { canceled, filePaths } = await dialog.showOpenDialog();if (!canceled) {return filePaths[0];}
}function createWindow() {const mainWindow = new BrowserWindow({webPreferences: {preload: path.join(__dirname, "preload.js"),},});mainWindow.loadFile("index.html");
}app.whenReady().then(() => {//会把处理完成的消息返回给渲染进程ipcMain.handle("dialog:openFile", handleFileOpen);createWindow();
});
  1. 主进程到渲染器进程:将消息从主进程发送到渲染器进程时,需要指定是哪一个渲染器接收消息。 消息需要通过其 ·WebContents 实例·发送到渲染器进程。 此 WebContents 实例包含一个 ·send ·方法,其使用方式与· ipcRenderer.send ·相同。如下实例是一个原生操作系统菜单控制的数字计数器。
index.htmlCurrent value: <strong id="counter">0</strong><script src="./renderer.js"></script>
renderer.js
const counter = document.getElementById("counter");window.electronAPI.onUpdateCounter((value) => {const oldValue = Number(counter.innerText);const newValue = oldValue + value;counter.innerText = newValue.toString();window.electronAPI.counterValue(newValue);
});
preload.js
const { contextBridge, ipcRenderer } = require("electron/renderer");
contextBridge.exposeInMainWorld("electronAPI", {onUpdateCounter: (callback) =>ipcRenderer.on("update-counter", (_event, value) => callback(value)),counterValue: (value) => ipcRenderer.send("counter-value", value),
});
main.js
const { app, BrowserWindow, Menu, ipcMain } = require("electron/main");
const path = require("node:path");function createWindow() {const mainWindow = new BrowserWindow({webPreferences: {preload: path.join(__dirname, "preload.js"),},});const menu = Menu.buildFromTemplate([{label: app.name,submenu: [{click: () => mainWindow.webContents.send("update-counter", 1),label: "Increment",},{click: () => mainWindow.webContents.send("update-counter", -1),label: "Decrement",},],},]);Menu.setApplicationMenu(menu);mainWindow.loadFile("index.html");// Open the DevTools.mainWindow.webContents.openDevTools();
}app.whenReady().then(() => {ipcMain.on("counter-value", (_event, value) => {console.log(value); // 主进程中输出打印});createWindow();
});

在这里插入图片描述

  1. 渲染器进程到渲染器进程:没有直接的方法可以使用 ipcMain 和 ipcRenderer 模块在 Electron 中的渲染器进程之间发送消息。将主进程作为渲染器之间的消息代理。 这需要将消息从一个渲染器发送到主进程,然后主进程将消息转发到另一个渲染器。从主进程将一个 MessagePort 传递到两个渲染器。 这将允许在初始设置后渲染器之间直接进行通信。

进程沙盒化

从 Electron 20 开始,渲染进程默认启用了沙盒,无需进一步配置。

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

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

相关文章

【AI绘画】教你一个完美的文生图方法,简单易学好上手,新手也能轻松掌握Stable Diffusion使用!

当我们还在思索&#xff0c; AI&#xff08;人工智能&#xff09;是否能替代人类的地位&#xff0c; 它已悄然无声&#xff0c; 融入我们生活的点滴细节。 在艺术创作领域&#xff0c; AI技术作为核心力量&#xff0c;展现其无尽的魅力。 AI换脸、AI影像&#xff0c;AI角色、A…

Nas实现软路由OpenWrt安装

文章目录 基本配置步骤 基本配置 NAS&#xff1a;TS-264C 宇宙魔方 步骤 1.下载软路由OpenWrt 下载地址&#xff1a;https://openwrt.org/ 2.下载好以后&#xff0c;需要下载虚拟盘转换工具&#xff08;StarWind V2V Convert&#xff09; 下载地址&#xff1a;https://…

sprintboot容器功能

容器 容器功能Spring注入组件的注解Component&#xff0c;Controller&#xff0c;Service&#xff0c;Repository案例演示 Configuration应用实例传统方式使用Configuration 注意事项和细节 Import应用实例 ConditionalConditional介绍应用实例 ImportResource应用实例 配置绑定…

10 SpringBoot 静态资源访问

我们在开发Web项目的时候&#xff0c;往往会有很多静态资源&#xff0c;如html、图片、css等。那如何向前端返回静态资源呢&#xff1f; 以前做过web开发的同学应该知道&#xff0c;我们以前创建的web工程下面会有一个webapp的目录&#xff0c;我们只要把静态资源放在该目录下…

C#——正则表达式详情

正则表达式 正则表达式: 列如判断一个字符串是不是手机号&#xff0c;或者密码是否包含大小写数字等这些要求&#xff0c;可以把这些条件写成一个表达式 创建正则表达式 string s1 "1234adsab1KHGFJD"; // 创建正则时需要在字符串前面加上 Regex r new Regex(&q…

【安卓】在安卓中使用HTTP协议的最佳实践

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 目录 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌…

btrace:binder_transaction+eBPF+Golang实现通用的Android APP动态行为追踪工具

一、简介&#xff1a; 在进行Android恶意APP检测时&#xff0c;需要进行自动化的行为分析&#xff0c;一般至少包括行为采集和行为分析两个模块。其中&#xff0c;行为分析有基于规则、基于机器学习、基于深度学习甚至基于大模型的方案&#xff0c;各有各的优缺点&#xff0c;不…

从零开始开发知识付费APP:在线教育系统源码详解

今天&#xff0c;小编将从零开始&#xff0c;详细讲解在线教育系统的源码开发过程&#xff0c;帮助你打造一款功能完善的知识付费APP。 一、需求分析与规划 1.1 市场调研 在开始开发之前&#xff0c;首先要进行市场调研&#xff0c;了解当前市场上的主要竞争对手和用户需求。…

SpringBoot使用jasypt实现数据库信息的脱敏,以此来保护数据库的用户名username和密码password(容易上手,详细)

1.为什么要有这个需求&#xff1f; 一般当我们自己练习的时候&#xff0c;username和password直接是爆露出来的 假如别人路过你旁边时看到了你的数据库账号密码&#xff0c;他跑到他的电脑打开navicat直接就是一顿连接&#xff0c;直接疯狂删除你的数据库&#xff0c;那可就废…

Redis数据结构学习

Redis 关于redis相关的技术文章我一直没什么思路 直到最近的端午节,我偶然和一个程序员朋友聊到了关于redis数据结构相关的知识点, 所以我决定写一篇文章记录一下 首先我们需要知道redis支持哪些数据类型 Strings (字符串)Lists(列表)Hashes(哈希)Sets(集合)Sorted Sets(有序…

通过语言大模型来学习LLM和LMM(四)

一、大模型学习 新的东西&#xff0c;学习的东西就是多&#xff0c;而且最简单最基础的都需要学习&#xff0c;仿佛一点基础知识都要细嚼慢咽&#xff0c;刨根问底&#xff0c;再加上一顿云里雾里的吹嘘&#xff0c;迷迷糊糊的感觉高大上。其实就是那么一回事。再过一段时日&a…

Java课程设计:基于swing的学生信息管理系统

文章目录 一、项目介绍二、项目展示三、源码展示四、源码获取 一、项目介绍 这款Java swing实现的学生信息管理系统和jsp版本的功能很相似&#xff0c;简单的实现了班级信息的增删改查&#xff0c;学生信息的增删改查&#xff0c;数据库采用的是mysql&#xff0c;jdk版本不限&…

Django+Vue.js怎么实现搜索功能

一.前言 类似这样的搜索功能 二.前端代码 <div class"form-container"><div class"form-group"><label for"departure-city">出发城市</label><select v-model"departureCity" id"departure-city&q…

C# Winform 用户控件,扩展控件,自定义控件综合实例

Control类是Windows窗体控件的基类&#xff0c;它提供了在 Windows 窗体应用程序中进行可视显示所需的基础结构&#xff0c;可以通过继承来扩展熟悉的用户控件和现有控件的功能。本列介绍三种不同自定义控件以及怎么创建他们。 自定义控件分类 用户控件&#xff1a;基本控件的…

Python 中国象棋游戏【含Python源码 MX_011期】

简介&#xff1a; 中国象棋是一种古老而深受喜爱的策略棋类游戏&#xff0c;也被称为中国的国粹之一。它在中国有着悠久的历史&#xff0c;起源可以追溯到几个世纪以前。Python 中国象棋游戏是一个用Python编程语言编写的软件程序&#xff0c;旨在模拟和提供中国象棋的游戏体验…

性能测试包括哪些方面?

性能测试、通过自动化测试工具模拟多种正常&#xff0c;峰值&#xff0c;以及异常的负载情况下对系统各项性能指标进行的测试。 负载测试、压力测试、容量测试都属于性能测试。 性能测试指标是衡量系统性能的评价标准 主要关注一些响应时间、并发用户/并发、点击率、吞吐量、…

【ARMv8/ARMv9 硬件加速系列 3.2 -- SVE 读写内存指令 st1b | st1w | st1w | st1d 使用介绍】

文章目录 SVE Load 和 Store 指令使用介绍LD1 加载指令ST1 存储指令PFR 预取指令参考示例LD1 加载示例ST1 存储示例 代码实例 SVE Load 和 Store 指令使用介绍 ARMv9架构中的SVE&#xff08;Scalable Vector Extension&#xff09;指令集为向量计算提供了强大支持&#xff0c;…

10W大奖等你瓜分,OpenTiny CCF开源创新大赛报名火热启动!

OpenTiny CCF开源创新大赛正式启幕&#xff01; &#x1f31f;10万奖金&#xff0c;等你来战&#xff01; &#x1f31f; &#x1f465;无论你是独行侠还是团队英雄&#x1f465; 只要你对前端技术充满热情&#xff0c; 渴望在实战中磨砺技能&#xff0c; 那么&#xff0c…

Day 23 669. 修剪二叉搜索树 108.将有序数组转换为二叉搜索树 538.把二叉搜索树转换为累加树

# 669. 修剪二叉搜索树 思路 相信看到这道题目大家都感觉是一道简单题&#xff08;事实上leetcode上也标明是简单&#xff09;。 但还真的不简单&#xff01; #递归法 直接想法就是&#xff1a;递归处理&#xff0c;然后遇到 root->val < low || root->val >…

SpringCloud微服务架构(eureka、nacos、ribbon、feign、gateway等组件的详细介绍和使用)

一、微服务演变 1、单体架构&#xff08;Monolithic Architecture&#xff09; 是一种传统的软件架构模式&#xff0c;应用程序的所有功能和组件都集中在一个单一的应用中。 在单体架构中&#xff0c;应用程序通常由一个大型的、单一的代码库组成&#xff0c;其中包含了所有…