深入理解 JavaScript 引擎与消息队列的底层原理
深入理解 JavaScript 引擎与消息队列的底层原理
JavaScript 是现代 Web 开发中最为重要的编程语言之一,它的运行和执行方式常常是开发者关注的重点。为了更好地理解 JavaScript 的执行过程,我们需要深入探索 JavaScript 引擎的工作原理,尤其是事件循环(Event Loop)、消息队列(Message Queue)以及它们如何协同工作来处理异步任务。
在这篇文章中,我们将深入分析 JavaScript 引擎的底层机制,并探讨消息队列与事件循环的工作原理,从而更好地理解 JavaScript 的异步行为和性能优化技巧。
一、JavaScript 引擎的基本工作原理
1.1 JavaScript 引擎概述
JavaScript 引擎是一个用来执行 JavaScript 代码的程序,负责将开发者编写的源代码转化为计算机可以理解的机器码并执行。在 Web 浏览器中,JavaScript 引擎是使 JavaScript 脚本能在浏览器中运行的核心部分。它通常和浏览器的渲染引擎共同工作,确保页面的结构和内容能动态更新。JavaScript 引擎并不是一个单一的程序,而是由多个组件和阶段构成的复杂体系。不同的浏览器采用不同的 JavaScript 引擎,但它们的工作原理大致相同。常见的 JavaScript 引擎包括:
- V8 引擎(Google Chrome、Node.js):这是 Google Chrome 使用的 JavaScript 引擎,也是 Node.js 中执行 JavaScript 的引擎。V8 采用 JIT(即时编译)技术来提高执行效率。
- SpiderMonkey 引擎(Mozilla Firefox):由 Mozilla 开发,支持 JIT 编译和解释执行。
- JavaScriptCore 引擎(Safari):由 Apple 开发,使用 JIT 技术和即时解释执行。
- Chakra 引擎(曾用于 Microsoft Edge):微软开发的引擎,后来的 Microsoft Edge 改用 Chromium 引擎,因此 Chakra 已不再更新。
尽管不同的引擎在细节上有所不同,JavaScript 引擎的基本组成和工作原理大致相同,通常包括解析器、编译器、执行环境和调用栈等组件。
1.2 JavaScript 引擎的核心组件
一个典型的 JavaScript 引擎包含多个组成部分,它们分别承担不同的任务,下面是其中最重要的几个组件:
1.2.1 解析器(Parser)
解析器的主要任务是将 JavaScript 源代码转化为一种中间表示,即抽象语法树(AST)。在这个阶段,JavaScript 引擎会读取源代码并进行词法分析和语法分析。
- 词法分析(Lexical Analysis):将 JavaScript 源代码转化为一系列标记(tokens)。这些标记通常是程序中变量名、操作符、关键字、分隔符等组成的最小单位。例如,
const x = 10;
会被分解为const
、x
、=
、10
和;
等标记。 - 语法分析(Syntactic Analysis):根据 JavaScript 的语法规则,解析这些标记,构建出抽象语法树(AST)。AST 是代码的语法结构的树状表示,它保留了程序中每个元素之间的层次关系。
举个简单的例子:
const x = 10;
对应的抽象语法树(AST)可能会是这样的结构:
VariableDeclaration├── Identifier (x)└── Literal (10)
解析器的输出是 AST,这个 AST 会在后续的编译阶段使用。
1.2.2 编译器(Compiler)
编译器将 AST 转换为可以在计算机上执行的代码。具体来说,编译器会根据当前 JavaScript 引擎的优化策略,将 AST 转换为字节码或机器码。对于现代 JavaScript 引擎而言,通常会使用**即时编译(JIT,Just-In-Time Compilation)**技术。
- 即时编译(JIT):在执行过程中,JavaScript 引擎会将高频代码片段(热代码)编译成机器码。JIT 编译使得 JavaScript 的执行速度大幅提高,因为它只会编译程序中最常用的部分,而不是预先编译整个程序。
- 解释执行:对于不常执行的代码,JavaScript 引擎可能选择解释执行,而不是编译成机器码。这种方法更灵活,但执行效率较低。
V8 引擎就是通过这种混合编译的方式来提高执行效率的。它首先解释执行代码,随着代码的执行频率增高,JIT 编译器会将其转换为更高效的机器码。
1.2.3 执行环境(Execution Context)
每次 JavaScript 代码执行时,都会创建一个执行上下文。执行上下文保存着关于当前执行环境的所有信息,包括当前正在执行的函数、变量、作用域链等。执行上下文的生命周期与函数调用密切相关。
执行上下文通常有三种类型:
- 全局执行上下文(Global Execution Context):这是代码首次执行时创建的上下文。全局上下文是代码执行的起点,也是在 JavaScript 引擎中首次创建的执行上下文,所有全局变量和函数都会作为属性附加到全局执行上下文中。
- 函数执行上下文(Function Execution Context):每次调用一个函数时,JavaScript 引擎会为该函数创建一个新的执行上下文。这个上下文保存了函数的所有局部变量、参数以及当前的执行环境。
- Eval 执行上下文(Eval Execution Context):在严格模式下不推荐使用。执行
eval()
时,会创建一个新的执行上下文,这个上下文执行的代码会在当前的作用域链中查找和创建新的变量。
执行上下文有一个重要的特性,就是每次进入一个执行上下文时,JavaScript 引擎会生成一个执行上下文栈,也叫做调用栈(Call Stack),它记录着代码的执行顺序和当前执行的状态。
1.2.4 调用栈(Call Stack)
调用栈是一个后进先出(LIFO)的数据结构,用来追踪函数调用的执行顺序。每次函数被调用时,JavaScript 引擎会为其创建一个新的执行上下文,并将该上下文推入调用栈。函数执行完毕后,执行上下文会被弹出栈。
调用栈的工作过程如下:
- 执行一个函数时,创建一个新的执行上下文,将其压入栈中。
- 如果该函数调用了另一个函数,会为被调用的函数创建一个新的执行上下文并压入栈中。
- 函数执行完毕后,当前的执行上下文会被弹出栈,控制权返回给上一个执行上下文。
调用栈的最大深度通常是有限的,这也是为什么 JavaScript 中会出现“栈溢出”的错误(Stack Overflow),即函数递归调用的层数超过了调用栈的最大深度。
1.3 JavaScript 代码的执行过程
当 JavaScript 引擎开始执行代码时,它会按照以下顺序执行:
- 加载和解析:JavaScript 引擎加载源代码并通过解析器生成抽象语法树(AST)。AST 只是源代码的结构化表示,JavaScript 引擎并不会直接执行 AST,它还需要进行编译。
- 编译:编译器将 AST 转换为字节码或机器码。如果采用 JIT 编译,编译器会针对热点代码进行优化。
- 执行:执行代码时,JavaScript 引擎会通过调用栈管理当前正在执行的任务。每当一个函数被调用时,JavaScript 引擎会为其创建一个新的执行上下文并将其压入栈中。执行过程中如果遇到异步操作(例如 setTimeout 或 Promise),相关的回调会被推入消息队列中等待执行。
- 事件循环:在主线程空闲时,事件循环机制会从消息队列中取出任务并执行,确保异步任务能够得到执行。
1.4 总结
JavaScript 引擎的工作流程涉及多个复杂的组件,包括解析器、编译器、执行环境、调用栈等。它们共同协作,将 JavaScript 代码转换为可执行的机器码,并通过事件循环处理异步任务。理解这些底层原理对于开发高效、性能优越的 JavaScript 应用至关重要。通过了解 JavaScript 引擎如何解析、编译和执行代码,我们可以更好地理解异步编程、性能优化以及如何避免常见的运行时错误。
二、消息队列与事件循环
在现代 JavaScript 引擎中,消息队列(Message Queue)和事件循环(Event Loop)机制是处理异步任务的核心。这些机制使得 JavaScript 即便是单线程的,也能有效处理大量的异步任务,如用户输入、网络请求、文件读取和定时任务等。为了理解 JavaScript 如何在单线程中实现异步任务的并发执行,我们需要深入理解事件循环机制、消息队列、宏任务和微任务的工作原理。
2.1 异步任务与消息队列的基础
2.1.1 异步任务的来源
JavaScript 是一门单线程语言,这意味着它只能在一个时间点执行一个任务。然而,在现实的应用场景中,我们通常需要处理异步任务,这些任务的执行时间是不可预测的,比如:
- 网络请求:例如发送 HTTP 请求。
- 定时器任务:
setTimeout
和setInterval
。 - 用户输入事件:比如点击、滚动或键盘输入。
- 浏览器渲染:DOM 更新和绘制。
- 文件 I/O 操作:特别是在 Node.js 环境中。
为了处理这些异步任务,JavaScript 引擎使用了一个机制,它将这些异步操作推送到消息队列中,待主线程空闲时执行。这样,JavaScript 引擎就能够在保证主线程只执行一个任务的前提下,有效管理多个异步任务。
2.1.2 消息队列的结构
消息队列(或事件队列)是一个先进先出(FIFO,First-In-First-Out)的数据结构。它用于存储需要异步执行的任务。JavaScript 引擎会不断从消息队列中取出任务,并将它们依次放入执行上下文进行执行。
通常,JavaScript 引擎会维护多个消息队列,用于存放不同类型的异步任务。最常见的包括:
- 宏任务队列(Macrotask Queue):存放宏任务,宏任务通常是较大的任务,例如定时器回调、DOM 事件、用户输入、I/O 操作等。
- 微任务队列(Microtask Queue):存放微任务,微任务通常是较小的任务,如
Promise
的.then()
或.catch()
回调、MutationObserver
回调等。
消息队列中的任务会按照它们被添加的顺序依次执行,确保所有的异步任务都有机会按顺序执行。
2.2 事件循环(Event Loop)
事件循环是 JavaScript 的核心机制之一,负责管理主线程的执行和消息队列中的任务。事件循环的作用是从消息队列中取出任务并将它们执行,从而使得异步任务得以执行。理解事件循环如何运作是理解 JavaScript 异步编程的关键。
2.2.1 事件循环的工作流程
事件循环的运行过程可以概括为以下几个步骤:
- 执行同步代码:首先,JavaScript 引擎会执行同步代码(即不依赖其他操作的代码)。同步代码会直接推入调用栈(Call Stack)并顺序执行。
- 检查调用栈是否为空:事件循环会不断检查调用栈(Call Stack)。如果栈中有函数正在执行,事件循环会等待当前函数执行完毕。
- 处理微任务:当调用栈为空时,事件循环会优先处理微任务队列。微任务包括
Promise
的回调、MutationObserver
的回调等。微任务的执行优先级高于宏任务,事件循环会执行所有微任务,直到微任务队列为空。 - 处理宏任务:一旦微任务队列为空,事件循环会检查宏任务队列。宏任务队列包括定时器回调(如
setTimeout
)、用户事件回调、I/O 操作回调等。事件循环会依次执行宏任务。 - 更新渲染:在执行完宏任务后,浏览器(或 JavaScript 引擎)会进行渲染更新。这包括计算样式、重绘页面和更新 DOM 树等。
- 重复循环:事件循环会继续重复上述过程。每次循环都会检查调用栈和消息队列的状态,确保任务被逐一执行。
2.2.2 为什么需要事件循环?
JavaScript 是单线程的,这意味着它无法并发地处理多个任务。事件循环为了解决这一问题,引入了任务队列机制,使得 JavaScript 能够处理多个异步任务。例如,当 JavaScript 执行网络请求时,它不会阻塞其他代码的执行;网络请求的回调会被放入消息队列,在主线程空闲时执行。这种机制保证了 JavaScript 代码在执行时既能保持单线程的顺序执行,又能异步地处理大量的任务。
2.3 宏任务与微任务
在事件循环中,异步任务被分为宏任务(Macrotasks)**和**微任务(Microtasks)。这两者的区别主要在于它们的优先级和执行时机。我们来逐一讲解它们的特点。
2.3.1 宏任务(Macrotasks)
宏任务是较大且耗时的任务,它们通常是“较重”的操作,比如:
setTimeout
/setInterval
:这两个函数会将回调函数放入宏任务队列,等待事件循环去执行。- DOM 事件:例如用户点击、输入框键入、窗口调整大小等,都会作为宏任务处理。
- I/O 操作:例如读取文件或从数据库获取数据,这些操作的回调通常也是宏任务。
宏任务的执行顺序是基于它们加入队列的顺序,事件循环每次从宏任务队列中取出一个任务来执行。因此,如果一个宏任务的回调函数执行时比较耗时,会延缓后续宏任务的执行。
2.3.2 微任务(Microtasks)
微任务是较轻、执行时间较短的任务,通常在当前宏任务执行完后、下一个宏任务开始前执行。微任务的执行优先级高于宏任务。常见的微任务包括:
Promise
回调:Promise.then()
、Promise.catch()
和Promise.finally()
等回调函数会被放入微任务队列。MutationObserver
:用于观察 DOM 变化的回调。
微任务在事件循环中执行的优先级高于宏任务,这意味着每次事件循环处理完一个宏任务后,会立即执行所有排队的微任务,直到微任务队列为空。
2.3.3 执行顺序
事件循环的执行顺序通常如下所示:
- 执行一个宏任务(例如定时器回调、I/O 操作等)。
- 执行所有微任务,直到微任务队列为空。
- 执行渲染更新(例如 DOM 更新、样式计算、页面重绘等)。
- 重复上述过程,直到所有任务都被执行完。
2.4 宏任务与微任务的执行顺序示例
为了更加清晰地理解宏任务和微任务的执行顺序,我们来看一个例子:
console.log('Start'); // 宏任务 1
setTimeout(() => {console.log('setTimeout'); // 宏任务 2
}, 0);
Promise.resolve().then(() => {console.log('Promise'); // 微任务 1
});
console.log('End'); // 宏任务 3
输出顺序:
Start
End
Promise
setTimeout
解释:
Start
和End
是同步代码,因此它们会被作为宏任务依次执行。setTimeout
的回调是一个宏任务,它会在当前宏任务执行完后被推入宏任务队列。Promise.resolve().then(...)
中的回调是一个微任务,它会在当前宏任务执行完毕后立即执行,微任务优先级高于宏任务。- 因此,
Promise
在setTimeout
之前被执行,输出顺序为:Start -> End -> Promise -> setTimeout
。
2.5 浏览器与 Node.js 中的事件循环差异
尽管浏览器和 Node.js 都采用了事件循环机制,但它们在事件循环的实现上存在一些差异。
2.5.1 浏览器中的事件循环
浏览器中的事件循环除了处理宏任务和微任务外,还会进行渲染更新,如样式计算、页面重排(reflow)和重绘(repaint)。在每次事件循环中,浏览器会在执行宏任务和微任务后执行渲染任务,确保页面能够实时更新。
2.5.2 Node.js 中的事件循环
Node.js 的事件循环与浏览器有所不同,因为它还需要处理大量的 I/O 操作。在 Node.js 中,事件循环会分为多个阶段,每个阶段都会有不同的队列来处理不同类型的任务。这些阶段包括:
- 定时器阶段:执行
setTimeout
和setInterval
的回调。 - I/O 队列阶段:执行 I/O 操作的回调,如文件读取、网络请求等。
- 检查阶段:执行
setImmediate
的回调。
这些阶段的执行顺序确保了 Node.js 能够高效地处理大量的 I/O 操作,同时保持异步任务的执行顺序。
2.6 总结
事件循环和消息队列是 JavaScript 处理异步任务的核心机制。通过事件循环,JavaScript 能够在单线程中高效地执行异步操作,保证了代码的顺序性和响应性。宏任务和微任务的优先级机制确保了任务能够按合理的顺序执行,而渲染更新则确保了页面能够在任务执行的过程中实时更新。理解这些机制对于编写高效、响应迅速的 JavaScript 应用至关重要。通过深入理解事件循环、消息队列、宏任务与微任务的执行顺序,开发者可以优化异步代码,避免性能瓶颈和逻辑错误,提升应用的性能和用户体验
三、消息队列与性能优化
理解 JavaScript 引擎、消息队列以及事件循环的工作原理之后,我们可以从应用性能优化的角度,探索如何利用这些底层机制来提升 JavaScript 应用的响应性、流畅度和性能。以下内容将深入探讨如何减少长时间运行的宏任务、合理使用微任务以及借助 Web Workers 实现多线程计算。
3.1 减少长时间运行的宏任务
3.1.1 宏任务执行的挑战
由于 JavaScript 是单线程执行的,每个宏任务的执行会占用整个主线程,直到该任务完成后,才能继续执行下一个任务。如果某个宏任务的执行时间过长,就会导致整个应用程序卡顿。尤其是在前端开发中,页面渲染、用户交互等依赖于主线程的执行,长时间阻塞主线程会极大影响用户体验。
例如,如果一个大规模的数据处理操作或动画计算阻塞了主线程,用户的点击、滚动等事件就无法及时响应,页面渲染可能会变得迟缓,用户体验显著下降。
3.1.2 拆分任务,避免阻塞主线程
为了避免长时间运行的宏任务阻塞主线程,任务拆分是常见的优化策略。我们可以将一个大的任务拆分成多个小的任务,每次执行一个小的任务,让主线程有机会去处理其它任务。常用的方法有 setTimeout
、setInterval
和 requestAnimationFrame
。
setTimeout
和setInterval
:这两个方法将任务推入宏任务队列,允许我们延迟执行某些操作,避免在主线程中直接执行长时间的任务。requestAnimationFrame
:这是一个浏览器提供的方法,专门用于在浏览器渲染下一帧时执行某些操作。它具有比setTimeout
更高的精度,并且在浏览器每帧的渲染周期内运行,非常适合用来做平滑动画。
3.1.3 拆分任务的示例
假设我们需要对一个庞大的数组进行计算和渲染,这会导致页面卡顿。如果直接在主线程中执行,页面将会长时间处于无响应状态。为了避免这个问题,可以将任务拆分为多个小任务,如下所示:
function processLargeData(data) {let index = 0;const chunkSize = 1000; // 每次处理1000个元素function processChunk() {const chunk = data.slice(index, index + chunkSize);// 执行对这一小块数据的处理操作console.log('Processing chunk:', chunk);index += chunkSize;if (index < data.length) {// 使用 setTimeout 分批次处理,防止阻塞主线程setTimeout(processChunk, 0);}}processChunk();
}const largeData = Array.from({ length: 100000 }, (_, i) => i);
processLargeData(largeData);
在这个示例中,processLargeData
函数将大数据集分成多个小数据块,通过 setTimeout
延迟执行每个小数据块的处理,确保主线程不会被长时间阻塞。每次处理完一个小块后,执行 setTimeout
让事件循环有机会处理其它的任务(比如用户输入、UI 渲染等)。
3.1.4 requestAnimationFrame
与动画性能优化
requestAnimationFrame
是专门为动画设计的优化方法。它会在浏览器渲染下一帧时执行回调函数,确保动画的平滑过渡,并且根据浏览器的帧率自动进行调节。
function animate() {// 这里是需要进行的每一帧的计算console.log('Animating...');// 请求下一帧动画requestAnimationFrame(animate);
}// 开始动画
animate();
通过使用 requestAnimationFrame
,我们确保动画渲染与浏览器的渲染周期同步,避免了由于 setTimeout
或 setInterval
使用时可能引发的视觉不流畅问题(例如每秒帧数不稳定,或在浏览器休眠时仍继续执行任务)。
3.2 合理使用微任务
3.2.1 微任务的优先级
微任务(Microtasks)优先于宏任务执行。微任务的执行机制使得它们能够比宏任务更早、更频繁地被执行。常见的微任务包括:
Promise
回调:Promise.then()
、Promise.catch()
等。MutationObserver
:监听 DOM 变化的 API。queueMicrotask
:显式将回调函数放入微任务队列。
由于微任务会在当前宏任务执行完毕后、下一次宏任务开始之前执行,因此微任务的执行是非常迅速和高效的。微任务的优先级较高,通常用于需要尽快完成的操作,例如处理 Promise 的回调。
3.2.2 微任务的过度使用可能带来的问题
虽然微任务的优先级高,且在执行时不会阻塞其他任务,但过度使用微任务可能导致性能瓶颈。尤其是当有大量微任务积压时,事件循环需要多次处理这些微任务,可能导致宏任务队列被延迟,进而影响页面的渲染更新。
例如,下面的代码会导致微任务堆积,影响页面的流畅性:
function run() {let i = 0;while (i < 1000000) {Promise.resolve().then(() => {console.log('Microtask', i);});i++;}
}run();
这段代码将导致大量微任务被迅速添加到队列中,直到队列被清空。这使得宏任务(比如 UI 渲染)会被长期延迟,导致页面无法及时更新,用户体验非常差。
因此,虽然微任务适合处理较为紧急的操作,但过度依赖微任务会导致性能下降。适度使用微任务,确保在合适的时机使用它们,是优化 JavaScript 性能的关键。
3.3 使用 Web Workers
3.3.1 为什么需要 Web Workers
JavaScript 是单线程执行的,这意味着它在执行计算密集型任务时会阻塞主线程,从而影响页面的响应性。尤其是在进行大规模计算(如图像处理、视频解码、大数据处理等)时,主线程将无法及时响应用户输入,导致页面卡顿、动画卡顿等不良体验。
为了克服这个问题,浏览器提供了 Web Workers。Web Workers 允许我们将计算密集型的操作移到独立的线程中执行,从而避免主线程被阻塞。
3.3.2 Web Workers 的工作原理
Web Workers 是在后台线程中运行的 JavaScript 实例。它们不直接访问 DOM 或主线程的 UI,但可以与主线程进行通信。主线程与 Web Worker 通过消息传递机制(postMessage 和 onmessage)来交换数据。
Web Worker 的优势在于它能够在后台并行处理耗时操作,并在任务完成时将结果返回给主线程。这样,主线程可以专注于处理 UI 渲染和用户交互,从而提高性能。
3.3.3 Web Worker 示例
假设我们需要进行复杂的计算,并且希望将其交给 Web Worker 处理:
// 主线程代码
const worker = new Worker('worker.js');worker.onmessage = function(event) {console.log('Worker response:', event.data);
};worker.postMessage('start'); // 向 Web Worker 发送消息
// worker.js (Web Worker 代码)
onmessage = function(event) {if (event.data === 'start') {let result = 0;for (let i = 0; i < 100000000; i++) {result += i;}postMessage(result); // 将计算结果返回给主线程}
};
在这个示例中,我们创建了一个 Web Worker,并通过 postMessage
向它发送一条消息。Web Worker 接收到消息后,进行计算并将结果返回给主线程。这样,主线程可以继续执行其他任务,如渲染页面、响应用户输入等,而不会受到计算任务的阻塞。
3.3.4 Web Workers 的局限性
虽然 Web Workers 可以将计算密集型的任务从主线程中移除,但它们也有一定的局限性。主要包括:
- 不能直接访问 DOM:Web Worker 无法直接操作 DOM,因此需要主线程通过消息传递来进行 DOM 操作。
- 跨线程通信开销:主线程和 Web Worker 之间的通信是通过消息传递完成的,这可能会带来一定的性能开销。
尽管如此,Web Workers 仍然是解决计算密集型任务和提高 JavaScript 性能的重要工具。
3.4 总结
通过了解 JavaScript 的消息队列和事件循环机制,我们可以采取一系列性能优化策略来提升应用的响应性和流畅度。以下是几个关键的优化技巧:
- 减少长时间运行的宏任务:通过任务拆分(如使用
setTimeout
或requestAnimationFrame
)来避免阻塞主线程,保证页面的流畅性。 - 合理使用微任务:利用微任务的高优先级来处理重要操作,但避免过多的微任务堆积,以免影响宏任务的执行。
- 使用 Web Workers:对于计算密集型任务,使用 Web Workers 将任务交给后台线程处理,避免阻塞主线程,提升应用的性能。
优化 JavaScript 应用的性能不仅是为了提升速度,更是为了提升用户体验。在复杂的前端应用中,合适地应用这些优化策略,能显著改善响应性,提供更加流畅和快速的用户体验。
四、结语
理解 JavaScript 引擎和消息队列的底层原理,对于开发高性能和响应迅速的 Web 应用至关重要。通过掌握事件循环、宏任务、微任务等概念,我们能够更好地设计和优化异步操作,使得我们的应用能够高效、平滑地响应用户请求。在实际开发中,合理地利用异步操作、微任务和宏任务队列,将有助于提升应用的流畅性和性能。
希望这篇文章能够帮助你更好地理解 JavaScript 引擎的底层原理及其在异步操作中的应用。
点个小小关注支持一手 (^ _ ^)
相关文章:
深入理解 JavaScript 引擎与消息队列的底层原理
深入理解 JavaScript 引擎与消息队列的底层原理 JavaScript 是现代 Web 开发中最为重要的编程语言之一,它的运行和执行方式常常是开发者关注的重点。为了更好地理解 JavaScript 的执行过程,我们需要深入探索 JavaScript 引擎的工作原理,尤其…...
使用 ANSYS Forming 和 LS-DYNA 进行金属成形仿真简介
了解金属成型 金属成型是制造业中的关键过程,其中原材料通过变形转化为所需的形状。这可能包括冲压、弯曲和深拉等操作。这些工艺的质量和效率在很大程度上取决于对各种参数的精确控制,例如材料特性、工具几何形状和加工条件。为了优化这些参数并确保成功…...
001-mysql安装
[rootcentos701 ~]# hostname -I 10.0.0.200 172.17.0.1 [rootcentos701 ~]# hostname centos701 [rootcentos701 ~]# rpm -qa | grep mariadb [rootcentos701 ~]# rpm -e --nodeps mariadb-libs-5.5.65-1.el7.x86_64 [rootcentos701 ~]# useradd mysql -s /sbin/nologin #创建…...
以攻击者的视角进行软件安全防护
1. 前言 孙子曰:知彼知己者,百战不殆;不知彼而知己,一胜一负,不知彼,不知己,每战必殆。 摘自《 孙子兵法谋攻篇 》在2500 年前的那个波澜壮阔的春秋战国时代,孙子兵法的这段话&…...
Go 语言性能优化全解析
在当今的软件开发环境中,Go 语言(Golang)因其简洁的语法、高效的并发模型和快速的编译速度而备受青睐。然而,随着应用程序复杂性的增加,即使是在 Go 中也可能会遇到性能瓶颈。为了帮助开发者构建高性能的应用程序&…...
《智能体雏形开发(高阶实操)》二、智能体雏形开发
基于阿里云百炼平台开发智能体应用:生成日报与周报 在智能体开发中,生成结构化的日报与周报是一个典型的任务。本篇文章将基于阿里云百炼平台,结合 Python 开发环境,介绍如何开发一个从日志文件提取信息并生成摘要的智能体。我们将从需求分析、任务设计到核心功能实现逐步…...
【k8s】kubelet 和 API Server的关系
文章目录 概述1. # kubelet 和 API Server 之间的关系**1. 角色和功能****1.1 kubelet****1.2 API Server** **2. 交互关系****2.1 kubelet 从 API Server 获取指令****2.2 kubelet 向 API Server 上报状态****2.3 kubelet 与 API Server 的认证和授权** **3. 典型交互场景****…...
POSTGRESQL跟ORACLE语法区别和相同之处
跟ORACLE语法区别之处 1. Update和delete语法区别 Pg 和MySQL Update和delete的时候表名不能加别名 2. 插入数字类型不一样 ORACLE 对number类型的数据可以用’’ 字符串标记插入,但是PG不行,必须要进行正确的数据类型 3. SEQ使用不同 ORACEL的SEQ…...
Distance in Tree 树形dp练习(树中两点距离为k的数量板子)
Distance in Tree 题面翻译 题目大意 输入点数为 N N N一棵树 求树上长度恰好为 K K K的路径个数 输入格式 第一行两个数字 N , K N,K N,K,如题意 接下来的 N − 1 N-1 N−1行中,每行两个整数 u , v u,v u,v表示一条树边 ( u , v ) (u,v) (u,v) 输出格式 一个整数 a n…...
【MySQL】库的操作+表的操作
库的操作表的操作 1.库的操作 1.1创建数据库1.2删除数据库1.3查找数据库1.4修改数据库1.5数据库备份和恢复1.6查看连接情况 2.库的操作 2.1创建表2.2查看表结构2.3修改表2.4删除表 点赞???收藏???关注??? 你的支持是对我最大的鼓励,我们一起努力吧???…...
vue异步更新,$nextTick
如果将isShowEdit改为true,就会显示输入框和确认按钮、 如果isShowEdit为false的话就显示“大标题”和编辑 想要获取元素焦点,但是vue是异步更新,会出错显示this.$refs.inp是undefined,是因为input元素并没有更新完成,所以需要使用…...
【3D AIGC】Img-to-3D、Text-to-3D、稀疏重建(2024年文章汇总)
文章目录 1. Wonderworld:拓展图片边界,生成3D场景2. 3DTopia-XL:扩散模型辅助生成3. 3DGS-Enhancer: 通过视图一致2D Diffusion,提升无界3D Gaussian Splatting (NlPs2024 Spotlight)4. L3DG:Latent 3D Gaussian Diff…...
简单的springboot使用sse功能
什么是sse? 1、SSE 是Server-Sent Events(服务器发送事件) 2、SSE是一种允许服务器主动向客户端推送实时更新的技术。 3、它基于HTTP协议,并使用了其长连接特性,在客户端与服务器之间建立一条持久化的连接。 通过这条连接&am…...
Nginx 防止IP伪造,绕过IP限制
背景介绍 在使用Nginx时,需要将IP地址转发到后置应用中,往往需要增加配置 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 在后端程序通过读取请求头里的X-Forwarded-For来获取用户客户端IP。 public String getRemortIP(HttpServle…...
原生js仿el-table动态表头
解决动态表头数据量过大导致页面卡顿的问题解决固定前几列导致表头设置宽度失效或者错位的问题功能: 固定前几列合并指定单元格 <div class"tableJoint2"><div><table id"tableData"></table></div><div>…...
【opencv入门教程】9.视频加载
文章选自: 一、VideoCapture类 用于从视频文件、图像序列或摄像头捕获视频的类。函数:CV_WRAP VideoCapture();brief 默认构造函数CV_WRAP explicit VideoCapture(const String& filename, int apiPreference CAP_ANY);brief 使用 API 首选项打开…...
数据结构 ——无头单链表
数据结构 ——无头单链表 一、无头单链表的定义与特性 1、单链表简介 单链表是一种常见的基础数据结构,它由一系列节点组成,每个节点包含数据部分和指向下一个节点的指针。无头单链表是单链表的一种变体,其特点是没有明确的头节点࿰…...
【UE5】制作插件 并调试【vs2022】
视频教程:好看视频-轻松有收获 https://www.youtube.com/watch?vIjpa9mI2b5I 原文:【UE】制作插件_ue插件-CSDN博客 C制作插件 1. 我们可以在C工程中创建更多类型的插件,这里我们选择“空白”作为模板来创建插件 点击“创建插件”按钮后…...
Prometheus 采集postgresql监控数据
postgres_exporter 前言 postgres_exporter 是一个用于监控 PostgreSQL 数据库的 Prometheus 导出器。它允许你收集有关 PostgreSQL 数据库性能和状态的指标,并将这些指标暴露给 Prometheus,从而可以在 Grafana 等可视化工具中进行展示和告警。 postgres_exporter download…...
网络分层模型( OSI、TCP/IP、五层协议)
1、网络分层模型 计算机网络是一个极其复杂的系统。想象一下最简单的情况:两台连接在网络上的计算机需要相互传输文件。不仅需要确保存在一条传输数据的通路,还需要完成以下几项工作: 发起通信的计算机必须激活数据通路,这包括发…...
POI遍历行所有单元格的两种方式,getPhysicalNumberOfCells方式有问题,勿用
今天看POI源码的时候,发现HSSFWorkbook类型的工作簿,行数据是用TreeMap<Integer, HSSFRow>存储的,列数据是用HSSFCell[]数组来存的;XSSFWorkbook类型的工作簿,行数据是用SortedMap<Integer, XSSFRow>存储的…...
Latex转word(docx)或者说PDF转word 一个相对靠谱的方式
0. 前言 投文章过程中总会有各种各样的要求,其中提供word格式的手稿往往是令我头疼的一件事。尤其在多公式的文章中,其中公式转换是一个头疼的地方,还有很多图表,格式等等,想想就让人头疼欲裂。实践中摸索出一条相对靠…...
敖汉宝塔油页岩露天矿山安全自动化监测
1. 项目简介 本次项目位于内蒙古自治区赤峰市敖汉旗宝国吐乡大青山村,地理位置好。主营许可经营项目:无一般经营项目:页岩油生产;页岩油、润滑油、建筑材料(不含油漆)销售等单位规模1-20人,单位…...
Android笔记【14】结合LaunchedEffect实现计时器功能。
一、问题 cy老师第五次作业 结合LaunchedEffect实现计时器功能。要求:动态计时,每秒修改时间,计时的时间格式为“00:00:00”(小时:分钟:秒)提交源代码的文本和运行截图…...
三维重建(单目、双目、多目、点云、SFM、SLAM)
1 相机几何与标定1.1 相机模型中的坐标系1.2 四种坐标系之间的转换1.3 相机内参1.4 相机标定 2 传统三维重建2.1 RGBD三维重建2.1.1 KinectFusion2.1.2 BundleFusion 2.1 MVS三维重建2.2.1 COLMAP2.2.2 OpenMVS 3 点云三维重建3.1 3D点云任务3.2 点云数据3.3 特征提取3.3.1 Poi…...
软体机器人动态手内笔旋转研究
人工智能咨询培训老师叶梓 转载标明出处 软体机器人因其在安全互动方面的优势而备受关注,但在高速动态任务中却面临挑战。最近,卡内基梅隆大学机器人研究所的研究团队提出了一种名为SWIFT的系统,旨在通过学习和试错来实现软体机器人手的动态…...
福昕PDF低代码平台
福昕PDF低代码平台简介 福昕PDF 低代码平台是一款创新的工具,旨在简化PDF处理和管理的流程。通过这个平台,用户可以通过简单的拖拽界面上的按钮,轻松完成对Cloud API的调用工作流,而无需编写复杂的代码。这使得即使没有编程经验的…...
【笔记】Linux中使用到的一些操作
1、查找指定文件并执行删除 find . -name "checkpoint_*_*.pth" -type f -exec rm -f {} \; 2、查看每个文件夹占用空间 du -h --max-depth1 3、移动文件 mv valid.zip ./xg mv 文件 目标位置 4、删除文件夹 rmdir folder rm -r folder # 递归删除文件夹下所有内容…...
深入浅出:PHP中的表单处理全解析
引言 在Web开发的世界里,表单是用户与服务器之间交互的重要桥梁。它们允许用户提交信息,并通过后端语言(如PHP)进行处理。本文将带你深入了解PHP中的表单处理,从基础的创建和提交到高级的安全措施和实用技巧ÿ…...
智已汽车x-signature 登录算法 签到
智已汽车x-signature 登录算法 签到 python代码成品...
一、测试工具LoadRunner Professional脚本编写-录制前设置
设置基于URL的脚本 原因:基于HTML的脚本会导致login接口不能正确录制 设置UTF-8 原因:不勾选此项会导致脚本中文变为乱码...
LSTM+改进的itransformer时间序列预测模型代码
代码在最后 本次设计了一个LSTM基于差分多头注意力机制的改进的iTransformer时间序列预测模型结合了LSTM(长短期记忆网络)和改进版的iTransformer(差分多头注意力机制),具备以下优势: 时序特征建模能力&am…...
linux中 Systemd 和 cgroups 的关系详解
systemd 是 Linux 的一个初始化系统和服务管理器,它依赖于 Linux 内核的 cgroups(Control Groups)功能来实现对系统资源的高效管理。以下是对两者关系的详细解读: 1. 什么是 cgroups? cgroups 是 Linux 内核提供的一种…...
发布Apache2.4** 局域网无法访问
1。 防火墙关闭 或者 设置入站规则 2,查看httpd.conf 文件 设置配置 原 Listen 80 修改成 Listen 192.168.31.127:90 3.确保 本地IP 是否正确...
【JAVA】Java高级:多数据源管理与Sharding:在Spring Boot应用中实现多数据源的管理
一个电商平台可能需要一个数据库来存储用户信息,另一个数据库来存储订单信息,甚至可能还有一个数据库用于数据分析。这种情况下,如何在Spring Boot应用中实现多数据源的管理就显得尤为重要。 1. 多数据源管理的重要性 在实际应用中…...
Android 分词的两种方式
前言: 本文分别介绍了原生和三方(Jieba)两种分词方式的使用和注意事项 1、安卓原生BreakIterator分词 比较简单,但是效果不太行 /*** 功能:原生分词* 参数:text:需要分词的语句* 返回值:return…...
【开源免费】基于SpringBoot+Vue.JS中小型医院网站(JAVA毕业设计)
博主说明:本文项目编号 T 078 ,文末自助获取源码 \color{red}{T078,文末自助获取源码} T078,文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析…...
数据结构代码归纳
1.线性表 线性表的顺序表示 定义与初始化 typedef struct SqList{ElemType data[MaxSize];//ElemType *data 开动态数组 int length; }Sqlist; void InitList(SqList &L){L.length0;//若静态数组//若动态数组 //L.data(ElemType*)malloc(sizeof(ElemType)*MaxSize); }…...
2024-金盾信安杯线上赛 WP
Misc 大赛宗旨 记事本打开,一眼零宽隐写 B 神工具一把梭,得到一串 base 编码 base64 解码得到 flag flag 值:flag{5d5555fa-1303-4b43-8eef-d6ea7c64c361} esab 根据题目 esab 可以发现这正是 base 的逆向,所以可以先逆向一下…...
iOS如何自定义一个类似UITextView的本文编辑View
对于IOS涉及文本输入常用的两个View是UITextView和UITextField,一个用于复杂文本输入,一个用于简单文本输入,在大多数开发中涉及文本输入的场景使用这两个View能够满足需求。但是对于富文本编辑相关的开发,这两个View就无法满足自…...
JavaWeb文件上传
文件上传总览 文件上传主要是指将本地文件(包括但不限于图片、视频、音频等)上传到服务器,提供其他用户浏览或下载的过程。在日常生活中,我们在很多情况下都需要使用文件上传功能,比如:发微博、发朋友圈等…...
C#实现1ms定时器不精准?如何实现一个高性能高精度的1ms定时器?(附完整示例Demo)
在C#日常开发中,我们经常需要使用定时器(Timer)进行周期性任务的执行。 例如,每隔1秒打印一条日志,或每隔100毫秒执行某个数据刷新逻辑。 但是,当我们尝试在C#中实现一个1毫秒(1ms)…...
LeetCode 3. 无重复字符的最长子串
题目链接:3. 无重复字符的最长子串 首先想到的就是暴力破解,直接两层循环遍历,因为它说求无重复,那就可以用 set 来存储遍历到的字符,如果遍历到了同样的字符(在 set 中存在),就直接跳出第二层循环&#x…...
深度解析 Ansible:核心组件、配置、Playbook 全流程与 YAML 奥秘(上)
文章目录 一、ansible的主要组成部分二、安装三、相关文件四、ansible配置文件五、ansible 系列 一、ansible的主要组成部分 ansible playbook:任务剧本(任务集),编排定义ansible任务集的配置文件,由ansible顺序依次执…...
记一次由docker容器使得服务器cpu占满密码和密钥无法访问bug
Bug场景: 前几天在服务器上部署了一个免费影视网站,这个应用需要四个容器,同时之前的建站软件workpress也是使用docker部署的,也使用了三个容器。在使用workpress之前,我将影视软件的容器全部停止。 再使用workpress…...
功能篇:JAVA实现记住我功能
在Java Web应用程序中实现“记住我”功能,通常涉及以下几个步骤: 1. 创建一个持久化的标识符(如一个令牌或哈希值),并将其与用户账户关联。 2. 将这个标识符保存到客户端的cookie中。 3. 在服务器端,当用户…...
实现 DataGridView 下拉列表功能(C# WinForms)
本文介绍如何在 WinForms 中使用 DataGridViewComboBoxColumn 实现下拉列表功能,并通过事件响应来处理用户的选择。以下是实现步骤和示例代码。 1. 效果展示 该程序的主要功能是展示如何在 DataGridView 中插入下拉列表,并在选择某一项时触发事件。 2.…...
2024年上半年网络工程师综合知识真题及答案解析
2024年上半年网络工程师综合知识真题及答案解析 以下不属于5G网络优点的是()A.传输过程中消耗的资源少,对设备的电池更友好B.支持大规模物联网,能够连接大量低功耗设备,提供更高效的管理C.引入了网络切片技术,允许将物理网络划分为多个虚拟网络D.更好的安全性,采用更…...
数合平台功能-管理角色
前一阵,有朋友问到,看咱们产品的功能描述很强大,但很多功能看不到。为此,基于数据建模产品最新版本,和大家一起串一下产品的功能和使用路径。本节重点说一下管理角色有哪些功能 一、功能清单 从上图中可以看到&#x…...
LVGL9 开关控件 (lv_switch) 使用指南
文章目录 前言主体1. **控件概述**2. **控件的样式和组成部分**3. **使用控件**改变开关状态 4. **事件处理**5. **按键支持**6. **示例代码** 总结 前言 lv_switch 是 LittlevGL 提供的一个开关控件,外观类似一个小型滑块,常用于实现开关功能ÿ…...