超硬核五千字!彻底讲明白JavaScript中的异步和同步,以及JavaScript代码执行顺序

同步操作和异步操作是编程中处理任务的两种不同方式,它们主要区别在于控制流和对程序执行的影响。不知道大家是怎么理解JavaScript中的同步和异步的?JavaScript的代码执行顺序是怎么样?下面这段代码是同步还是异步的?

console.log('Start');
const response = await fetch('https://juejin.cn');
const data = await response.json();
console.log('Data received:', data);
console.log('End');

同步操作 (Synchronous)

定义: 同步操作会阻塞当前线程或进程,直到该操作完成。这意味着当一段代码执行同步操作时,后面的代码必须等待该操作完成才能继续执行。在同步操作中,任务按顺序执行,一个任务必须完成后才能执行下一个任务。这种方式会阻塞程序的执行,直到当前任务完成。

特点:

  • 简单直观,代码按照从上到下的顺序执行。
  • 在执行耗时操作时会阻塞其他任务,可能导致UI无响应(在前端JavaScript中)。

JavaScript示例:

console.log('Start');
function synchronousTask() {for (let i = 0; i < 1000000000; i++) { /* 耗时任务 */}console.log('Task done');
}
synchronousTask();
console.log('End');

在这个例子中,循环是一个简单的模拟耗时操作。当这段代码执行时,console.log('Start'); 先执行并打印 StartsynchronousTask(); 开始执行,直到循环结束,才会打印出 “End”。在此期间,无法处理其他任务或用户交互。

异步操作 (Asynchronous)

定义: 异步操作允许程序在等待某个操作完成的同时继续执行其他任务,不阻塞当前线程。异步操作通常用于处理I/O操作、网络请求、定时器等潜在的长时间操作。

特点:

  • 程序可以继续执行其他任务,提高应用的响应性和性能,特别是在处理I/O密集型任务时。
  • 代码逻辑更复杂,需要回调函数、Promises或async/await来处理异步流程。

我们从代码中理解异步,这里使用一个定时器,JavaScript示例:

console.log('Start');function asynchronousTask() {setTimeout(() => {console.log('Task done');}, 1000);
}asynchronousTask();console.log('End');

在这段代码中,执行顺序如下所示:

  1. console.log('Start'); 先执行并打印 Start
  2. asynchronousTask(); 开始执行,setTimeout 设置了一个异步任务,这个任务在 1 秒后执行,但不会阻塞程序
  3. console.log('End'); 立即执行并打印 End
  4. 1 秒后,异步任务完成,console.log('Task done'); 执行并打印 Task done

但是一般在写代码的时候,我们的异步操作肯定不是通过定时器完成的,下面给大家展示两种异步操作写法,分别如下所示:

1、使用 Promise 处理异步操作

console.log('Start');function asynchronousTask() {return new Promise((resolve) => {setTimeout(() => {resolve('Task done');}, 1000);});
}asynchronousTask().then(message => {console.log(message);
});console.log('End');

在这个例子中:

  1. asynchronousTask 返回一个 Promise,它在 1 秒后解决(resolve)
  2. console.log('Start');console.log('End'); 立即执行
  3. 1 秒后,Promise 被解决,console.log(message); 打印 Task done

2、使用 async/await 处理异步操作

console.log('Start');async function runAsyncTask() {const message = await asynchronousTask();console.log(message);
}runAsyncTask();console.log('End');

在这个例子中:

  1. async 函数 runAsyncTask 内部使用 await 等待 asynchronousTask 完成,但不会阻塞外部代码
  2. console.log('Start');console.log('End'); 立即执行
  3. 1 秒后,asynchronousTask 完成,console.log(message); 打印 Task done

现在是不是对同步和异步的概念有了基本的认识,咱们再回到文章最开始的代码,结论是那段代码不是同步的,而是异步的。在上面代码中,遇到 await 等待结果阻塞代码执行了,为什么不说它是同步?

为了更好地理解,可以将这段代码放在一个异步函数中执行:

async function fetchData() {console.log('Start');const response = await fetch('https://api.example.com/data');const data = await response.json();console.log('Data received:', data);console.log('End');
}fetchData();

我们先理解一下这个关键词:await关键字会暂停当前的异步函数,等待异步操作完成,但不会阻塞外部代码,不会阻塞事件循环

在这个例子中,fetchData是一个异步函数,尽管await关键字会暂停它的执行,但它不会阻塞整个程序的执行。因此,这段代码是异步的,而不是同步的。假设fetchData函数后面有一个输出,它可能先执行的。

await 仅会暂停当前异步函数的执行,让出控制权给事件循环,以便处理其他任务。

当一个异步函数遇到 await 时,它会暂停该函数的执行,等待 Promise 被解决(resolved)或者被拒绝(rejected)。然而,这种暂停并不等同于传统的同步阻塞,因为其他任务依然可以执行。

咱们接下来通过一段代码来展示什么是阻塞整个程序的执行。在JavaScript中,阻塞代码通常是指那些在执行时会阻塞事件循环,导致其他任务无法执行的代码。常见的例子包括使用同步的I/O操作或长时间运行的计算。

以下是一个使用同步I/O操作的例子,这种操作会阻塞整个程序的执行:

const fs = require('fs');function readFileSync() {// 打印"Start"到控制台console.log('Start');// 同步读取文件的内容// 在文件读取完成之前,这行代码会阻塞事件循环,其他任务无法执行const data = fs.readFileSync('/opt/xiaodou.txt', 'utf8');// 打印读取到的文件内容到控制台console.log('File data:', data);// 打印"End"到控制台console.log('End');
}readFileSync();

在这个例子中,fs.readFileSync是一个同步的文件读取操作,它会阻塞事件循环,直到文件读取完成。在读取文件的过程中,其他任务无法执行,整个程序的执行被阻塞。

这段代码的执行顺序是严格线性的,整个程序会在读取文件时被阻塞,直到读取操作完成。

为了对比,可以看一下使用异步I/O操作的代码,这样的代码不会阻塞事件循环:

const fs = require('fs');function readFileAsync() {console.log('Start');// 读取文件的异步操作,这不会阻塞事件循环fs.readFile('/opt/xiaodou.txt', 'utf8', (err, data) => {if (err) {console.error('Error reading file:', err);return;}console.log('File data:', data);});console.log('End');
}readFileAsync();

在这个例子中,fs.readFile是一个异步的文件读取操作,它不会阻塞事件循环,程序可以继续执行其他任务。

现在对JavaScript中的同步是不是有一些理解:导致整个程序的执行被阻塞是同步,只是暂停当前函数执行是异步,使用await关键字时,它会暂停当前异步函数的执行,等待异步操作完成,但不会阻塞事件循环,其他任务可以继续执行。

我们来看一下阻塞整个程序的代码,不仅会阻塞当前函数,还会阻塞整个事件循环,影响所有其他任务的执行,咱们现在在上面的同步函数中增加一个定时器,那么你猜猜定时器还能定时执行吗?

修改后的代码如下所示:

const fs = require('fs');function readFileSync() {console.log('Start');// 设置一个定时器,计划在1秒后执行setTimeout(() => {console.log('Timer executed');}, 1000);// 同步读取文件的操作,这会阻塞事件循环const data = fs.readFileSync('/opt/xiaodou.txt', 'utf8');console.log('File data:', data);console.log('End');
}readFileSync();

在这个例子中,fs.readFileSync是一个同步操作,它会阻塞事件循环,假设文件在1秒后无法读取完成,那么定时器无法在预定的1秒后执行。只有当文件读取操作完成后,定时器才会有机会执行。

事件循环是啥?

在上面我们一直提到事件循环,事件循环(Event Loop)是JavaScript运行时的一个重要机制,它允许非阻塞的异步编程,即使JavaScript是单线程的。事件循环负责管理和调度异步操作的执行,使得异步任务能够在任务完成后被处理,而不会阻塞主线程。

事件循环的工作原理

调用栈(Call Stack)

  • JavaScript引擎有一个调用栈,这是一个LIFO(后进先出)数据结构,用于跟踪正在执行的函数。
  • 当一个函数被调用时,它会被推入调用栈,当函数执行完成后,它会从调用栈中弹出。

任务队列(Task Queue)

  • 任务队列是一个FIFO(先进先出)数据结构,用于存储等待执行的回调函数。
  • 异步操作(如定时器、网络请求、事件处理等)完成后,其回调函数会被放入任务队列中。

事件循环(Event Loop)

  • 事件循环不断地检查调用栈是否为空。
  • 如果调用栈为空,并且任务队列中有待处理的任务,事件循环会将任务队列中的第一个任务移到调用栈中执行。

是不是感觉很难理解呢?接下来咱们结合代码理解一这一块的内容。

1、简单的示例

还是使用定时器的代码示例,说明一下事件循环的工作原理:

console.log('Start');setTimeout(() => {console.log('Timer executed');
}, 1000);console.log('End');

执行过程

调用栈 任务队列 事件循环 console.log('Start') 输出 "Start" setTimeout 设置定时器(1秒后回调) console.log('End') 输出 "End" 1秒后 超时回调函数 将回调函数推入调用栈 执行回调函数 输出 "Timer executed" 调用栈 任务队列 事件循环

输出结果

Start
End
Timer executed

2、复杂的代码

让我们看一个更复杂的例子,包含多个异步操作:

console.log('Start');setTimeout(() => {console.log('Timeout 1');
}, 500);setTimeout(() => {console.log('Timeout 2');
}, 100);Promise.resolve().then(() => {console.log('Promise 1');
});Promise.resolve().then(() => {console.log('Promise 2');
});console.log('End');

执行过程

调用栈 任务队列 微任务队列 事件循环 console.log('Start') 输出 "Start" setTimeout (500ms) 超时回调 1 (500ms) setTimeout (100ms) 超时回调 2 (100ms) Promise.resolve().then Promise 回调 1 Promise.resolve().then Promise 回调 2 console.log('End') 输出 "End" 检查微任务队列 执行 Promise 回调 1 输出 "Promise 1" 执行 Promise 回调 2 输出 "Promise 2" 100ms 后 执行超时回调 2 输出 "Timeout 2" 500ms 后 执行超时回调 1 输出 "Timeout 1" 调用栈 任务队列 微任务队列 事件循环

输出结果

Start
End
Promise 1
Promise 2
Timeout 2
Timeout 1

同学们,是不是发现个有趣的东西,这里多了一个微任务队列,那么微任务队列是什么?和任务队列是什么关系?

微任务和宏任务又是啥?

在JavaScript中,微任务(microtasks)和宏任务(macrotasks)是事件循环中处理异步任务的两种类型。它们代表了不同优先级的任务队列,事件循环会按照特定的顺序执行这些任务。

宏任务(Macro Task)

这个实际上就是咱们之前提到的任务队列中的任务。宏任务是那些在每个执行栈执行完毕后,从事件队列中取出并执行的任务。宏任务的执行频率低于微任务,因为它们需要等待整个执行栈清空后再执行。它们通常包括以下几类操作:

  • setTimeout
  • setInterval
  • setImmediate()(Node.js特有)
  • requestAnimationFrame()(浏览器特有)
  • I/O 操作
  • UI渲染(浏览器)
  • 其他一些异步任务

宏任务会被推入到任务队列中,事件循环会从任务队列中依次取出宏任务并执行。简单记忆就是:需要较长时间才来完成的任务,毕竟宏伟的工程往往需要很长的时间

微任务(Microtasks)

微任务是一些需要在当前任务执行完毕后立即执行的任务。它们通常是由Promises、process.nextTick(Node.js特有)或者MutationObserver等机制产生的。微任务队列优先级高于宏任务队列,这意味着在每个宏任务执行完毕后,事件循环会优先处理微任务队列中的所有任务,然后再处理下一个宏任务。它们通常包括以下几类操作:

  • Promises的.then().catch().finally()回调
  • process.nextTick()(Node.js)
  • queueMicrotask()(浏览器和Node.js)
  • MutationObserver(用于监听DOM变化)

微任务会被推入到微任务队列中,事件循环在每次执行完一个宏任务后,会检查并执行所有微任务,直到微任务队列为空。简单速记:微任务是指哪些需要尽快被完成的任务,小事要尽快做,拖久了就变大事了

干说有点费劲,给同学们来张流程图描述事件循环的基本原理:

有任务
无任务
有微任务
无微任务
有宏任务
无宏任务
开始事件循环
同步任务队列
执行同步任务
检查微任务队列
任务执行完毕
执行微任务
检查宏任务队列
执行宏任务
等待新任务

这是一个简化的时序图,事件循环的主要步骤如下:

  1. 开始事件循环:JavaScript引擎开始执行代码。

  2. 同步任务队列:引擎首先检查同步任务队列(实际上是调用栈中的任务),执行队列中的任务。

  3. 执行同步任务:引擎开始执行同步任务,直到队列为空。

  4. 检查微任务队列:同步任务执行完毕后,引擎检查微任务队列。

  5. 执行微任务:如果有微任务(如Promise的.then()回调),引擎会执行这些微任务。

  6. 检查宏任务队列:微任务执行完毕后,引擎检查宏任务队列。

  7. 执行宏任务:如果有宏任务(如setTimeout回调),引擎会执行这些宏任务。执行完毕后再次检查微任务队列。

  8. 等待新任务:如果宏任务执行完毕,引擎会等待新的任务(如新的异步操作或宏任务)。

  9. 循环:引擎会不断地循环执行上述步骤。

同学们这时候会不会有很多疑问,如果觉得上面的文字还不好理解,咱们接下来跟着代码走一遍。

代码示例讲解

咱们还是在上面代码的基础上做修改,这里增加一个包含await的方法,代码如下所示:

console.log('Start'); // 同步任务,立即执行setTimeout(() => {console.log('Timeout 1'); // 宏任务,500ms后执行
}, 500);setTimeout(() => {console.log('Timeout 2'); // 宏任务,100ms后执行
}, 100);async function asyncFunction() {console.log('Async Function Start'); // 同步任务,立即执行await Promise.resolve(); // 微任务,立即执行console.log('Async Function End'); // 微任务,放入微任务队列
}asyncFunction(); // 调用异步函数Promise.resolve().then(() => {console.log('Promise 1'); // 微任务,放入微任务队列
});Promise.resolve().then(() => {console.log('Promise 2'); // 微任务,放入微任务队列
});console.log('End'); // 同步任务,立即执行

时序图

调用栈 微任务队列 宏任务队列 console.log('Start') setTimeout(..., 500) setTimeout(..., 100) asyncFunction() console.log('Async Function Start') await Promise.resolve() console.log('Async Function End') Promise.resolve().then(...) console.log('Promise 1') Promise.resolve().then(...) console.log('Promise 2') console.log('End') 调用栈为空,检查微任务队列 console.log('Promise 1') console.log('Promise 2') console.log('Async Function End') 微任务队列为空,检查宏任务队列 100ms后 console.log('Timeout 2') 500ms后 console.log('Timeout 1') 调用栈 微任务队列 宏任务队列

详细解释一下代码中的任务都有哪些:

同步任务

  • console.log('Start'):立即执行,输出 “Start”。
  • setTimeout(..., 500):注册一个500ms后的宏任务。
  • setTimeout(..., 100):注册一个100ms后的宏任务。
  • asyncFunction():调用异步函数,输出 “Async Function Start”。
  • await Promise.resolve():注册一个微任务。
  • Promise.resolve().then(...):注册两个微任务。
  • console.log('End'):立即执行,输出 “End”。

微任务

  • Promise 1:输出 “Promise 1”。
  • Promise 2:输出 “Promise 2”。
  • Async Function End:输出 “Async Function End”。

宏任务

  • Timeout 2:100ms后输出 “Timeout 2”。
  • Timeout 1:500ms后输出 “Timeout 1”。

代码运行输出结果如下所示:

Start
Async Function Start
End
Promise 1
Promise 2
Async Function End
Timeout 2
Timeout 1

脑洞大开,搞事情

咱们能写一个阻塞事件循环的函数吗?

现在我们已经了解了基本原理,那么我们肯定可以搞点事情,我们可以使用循环阻止其他任务的执行,如下所示,这个函数会在指定的时间内阻塞事件循环,使得其他任务(包括异步操作和定时器)无法执行。

function blockEventLoop(duration) {const startTime = Date.now();while (Date.now() - startTime < duration) {// 这个循环会一直运行,直到达到指定的持续时间}console.log(`Blocked for ${duration} ms`);
}// 示例用法
console.log('Start');setTimeout(() => {console.log('Timeout executed');
}, 1000);blockEventLoop(3000);  // 阻塞事件循环3秒console.log('End');

我们来分析一下执行过程

  1. 开始执行console.log('Start'); 被推入调用栈,执行并输出 “Start”,然后从调用栈中弹出。

  2. 设置定时器setTimeout 被推入调用栈,设置一个1秒后的定时器。定时器的回调函数被注册,并计划在1秒后执行。最后setTimeout 从调用栈中弹出。

  3. 阻塞事件循环blockEventLoop(3000) 被推入调用栈,开始执行。进入while循环,持续3秒,期间事件循环被阻塞,无法处理其他任务。3秒后,while循环结束,输出 “Blocked for 3000 ms”。最后blockEventLoop 从调用栈中弹出。

  4. 继续执行console.log('End'); 被推入调用栈,执行并输出 “End”,然后从调用栈中弹出。

  5. 事件循环处理定时器:由于事件循环被阻塞了3秒,1秒后的定时器未能在预定时间执行。事件循环恢复后,定时器的回调函数被移到调用栈中执行,输出 “Timeout executed”。

代码输出结果如下所示,不知道你对了吗?

Start
Blocked for 3000 ms
End
Timeout executed

注意事项

阻塞事件循环会导致所有其他任务无法执行,不能瞎搞,尤其是在处理用户界面或需要高响应性的应用程序中。不然会被用户骂的。

拓展:JavaScript和Java在同步和异步编程上的差异

因为我之前是做Java开发,所以在这里增加一块两者的对比,有兴趣的可以看一看,JavaScript和Java在处理同步和异步操作方面确实有一些差异,主要体现在它们的运行时环境和编程模型上。

JavaScript中的同步和异步

JavaScript是单线程的,这意味着它一次只能执行一个任务。为了处理异步操作,JavaScript依赖于事件循环(Event Loop)机制。事件循环允许JavaScript在等待异步操作(如网络请求、定时器等)完成时继续执行其他任务,从而实现非阻塞的异步编程。

  • 同步操作:在调用栈中按顺序执行,每个操作必须等待前一个操作完成。
  • 异步操作:通过回调函数、Promise、async/await等机制实现,异步操作完成后会将回调函数放入任务队列,由事件循环调度执行。

Java中的同步和异步

Java是多线程的,支持并发编程。Java中的异步操作通常通过多线程实现,每个线程可以独立执行任务,从而实现并发和并行处理。Java也有丰富的并发工具,如ExecutorServiceFutureCompletableFuture等。

  • 同步操作:在一个线程中按顺序执行,每个操作必须等待前一个操作完成。
  • 异步操作:通过多线程、线程池、回调机制等实现,异步操作可以在不同的线程中并发执行。

Java中有没有事件循环?

严格来说,Java没有像JavaScript那样的内置事件循环机制。Java的异步操作主要依赖于多线程和并发工具,而不是事件循环。然而,在某些特定场景和框架中,Java也可以实现类似事件循环的机制。例如:

  • Swing和JavaFX:Java的GUI框架(如Swing和JavaFX)使用事件调度线程(Event Dispatch Thread,EDT)处理用户界面事件。这类似于事件循环,但仅用于处理GUI事件。
  • Netty:Netty是一个异步事件驱动的网络应用框架,它实现了自己的事件循环机制,用于处理网络I/O操作。

Java中的异步编程

让咱们看一个Java中的异步编程示例,使用CompletableFuture来实现异步操作:

import java.util.concurrent.CompletableFuture;public class AsyncExample {public static void main(String[] args) {System.out.println("Start");CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {try {Thread.sleep(1000); // 模拟异步操作System.out.println("Async Task Completed");} catch (InterruptedException e) {e.printStackTrace();}});future.thenRun(() -> System.out.println("Callback Executed"));System.out.println("End");// 等待异步任务完成future.join();}
}

执行过程

  1. 开始执行System.out.println("Start"); 输出 “Start”。

  2. 异步任务:使用CompletableFuture.runAsync启动一个异步任务,在另一个线程中执行。异步任务模拟执行1秒钟,然后输出 “Async Task Completed”。

  3. 注册回调:使用thenRun注册一个回调函数,当异步任务完成后执行,输出 “Callback Executed”。

  4. 继续执行System.out.println("End"); 输出 “End”。

  5. 等待异步任务完成:使用future.join()等待异步任务完成,确保程序不会过早退出。

输出结果如下所示:

Start
End
Async Task Completed
Callback Executed

现在你对JavaScript中的同步和异步有了解了吗?不知道大家还有什么疑问?

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

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

相关文章

浙大版PTA Python程序设计 题目与知识点整理(综合版)

目录 第一章 一、高级语言程序的执行方式 二、变量赋值与内存地址 三、字符编码 3.1 Unicode 3.2 ASCII&#xff08;American Standard Code for Information Interchange&#xff09; 四、编程语言分类按照编程范式分类 4.1 面向过程语言 4.2 面向对象语言 五、原码…

第零篇——数学到底应该怎么学?

目录 一、背景介绍二、思路&方案三、过程1.思维导图2.文章中经典的句子理解3.学习之后对于投资市场的理解4.通过这篇文章结合我知道的东西我能想到什么&#xff1f; 四、总结五、升华 一、背景介绍 宏观讲解数学定位&#xff0c;数学学习方式方法&#xff0c;再次详细学习…

Synctv安装过程中遇到的docker镜像国内无法pull的问题

0x01 docker无法直接拉取对应镜像文件的问题 docker目前国内网络环境无法直接拉去小众而且稍微前沿的docker镜像产品&#xff0c;这对很多折腾玩家及其不友好&#xff0c;我首先想到了替换成国内的docker镜像站&#xff0c;但是对于SyncTV这个产品的docker镜像文件还是无法拉去…

代码随想录——分割回文串(Leetcode 131)

题目链接 回溯 class Solution {List<List<String>> res new ArrayList<List<String>>();List<String> list new ArrayList<String>();public List<List<String>> partition(String s) {backtracking(s, 0);return res;}p…

SSM整合使用

文章目录 1. 项目创建2. spring(1) 导包(2) 配置类 3. mybatis(1) maven导包(2) mybatis配置文件(3) 连接配置文件(4) mapper映射文件(5) 在spring配置类中注册sqlsession的bean springMVC(1) maven导包(2) springMVC配置类(3) 初始化类 5. 测试(1) 创建3层架构(2) 编写Control…

从局部到全局:产品开发视角的转变与系统优化策略

一、研发背景 在科技产品开发领域&#xff0c;每一种产品都存在着多元化的开发方案可供选择&#xff0c;这要求开发者不断拓展视野&#xff0c;进行横向对比学习&#xff0c;以期找到最贴合市场需求、最具竞争优势的解决方案。以往&#xff0c;我们的研发团队一直立足于稳固而…

第三十章 使用 MTOM 进行附件 - 控制 MTOM 打包

文章目录 第三十章 使用 MTOM 进行附件 - 控制 MTOM 打包控制 MTOM 打包示例Web ServiceWeb Client 第三十章 使用 MTOM 进行附件 - 控制 MTOM 打包 控制 MTOM 打包 默认情况下&#xff0c;创建 MTOM 包时&#xff0c;它使用以下规则&#xff1a; 它以内联方式输出二进制字符…

分布式之日志系统平台ELK

ELK解决了什么问题 我们开发完成后发布到线上的项目出现问题时(中小型公司),我们可能需要获取服务器中的日志文件进行定位分析问题。但在规模较大或者更加复杂的分布式场景下就显得力不从心。因此急需通过集中化的日志管理,将所有服务器上的日志进行收集汇总。所以ELK应运而生…

HTML静态网页成品作业(HTML+CSS)——中华传统美德介绍网页(2个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;表格布局&#xff0c;未使用Javacsript代码&#xff0c;共有2个页面。…

学习java第一百零二天

Spring 面向切面编程&#xff08;Spring AOP&#xff09; 通过配置管理特性&#xff0c;Spring AOP 模块直接将面向方面的编程功能集成到了 Spring 框架中。所以&#xff0c;可以很容易地使 Spring 框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对…

YOLOv10涨点改进创新MSAM注意力,通道注意力升级,魔改CBAM

目录 1,YOLO v10介绍 1.1 C2fUIB介绍 1.2 PSA介绍 1.3 SCDown 2.自研MSAM 2.1 自研MSAM注意力介绍 3.MSAM如何加入到YOLOv8 3.1 MSAM加入ultralytics/nn/attention/MsAM.py 3.2 修改tasks.py1)首先进行引用定义 3.3 yolov10n-MSAM.yaml 3.4 yolov10n-PSMSAM.yaml 改…

Chain-of-Thought真能提高大模型的推理能力吗?

用于提高大语言模型&#xff08;LLM&#xff09;的推理、规划、算术等能力的思维链&#xff08;Chain-of-Thought、CoT&#xff09;技术&#xff0c;真的能帮助LLM一步步地回答问题吗&#xff1f;美国亚利桑那州立大学的研究人员近期发表了一篇论文[1]&#xff0c;论文根据实验…

net start mysql服务名无效

问题背景 起因是我的电脑因为停电烧坏了系统固态硬盘&#xff0c;再新装系统后&#xff0c;之前的MySQL服务无法通过下面的命令启动。 net start mysql # 报错&#xff1a;服务名无效 报错&#xff1a;服务名无效 报错信息 未找到&#xff1a;在Windows服务中找不到MySQL 找…

关于HTTP劫持,该如何理解、防范和应对

一、引言 HTTP劫持&#xff08;HTTP Hijacking&#xff09;是一种网络安全威胁&#xff0c;它发生在HTTP通信过程中&#xff0c;攻击者试图通过拦截、篡改或监控用户与服务器之间的数据流量&#xff0c;以达到窃取敏感信息或执行恶意操作的目的。今天我们就来详细了解HTTP劫持…

Google Earth Engine(GEE)——计算闪闪红星的ndvi的值和直方图(时序分析)

函数: ui.Chart.image.histogram(image, region, scale, maxBuckets, minBucketWidth, maxRaw, maxPixels)

数据库 | 事务

事务&#xff1a;要么做要么不做 开始语句&#xff1a;BEGIN TRANSACTION 结束语句&#xff1a;COMMIT&#xff08;正确&#xff09; ROLLBACK&#xff08;错误&#xff09; 4个性质&#xff1a;ACID A&#xff08;atomicity&#xff09; 原子性&#xff1a;一个事务要么不做…

AWS无服务器 应用程序开发—第十三章 小结2

电子邮件发送(Amazon SES、Amazon SNS、AWS Lambda) 注意点和易错点 SES 配置:确保域名验证和 DKIM 签名配置正确,避免邮件被标记为垃圾邮件。 SNS 配置:订阅和发布权限需要配置正确。 Lambda 权限:确保 Lambda 函数有正确的执行权限。 移除沙盒:需要大量发送邮件的时…

Ant Design Vue 动态表头和数据填充

创作动态表头和数据填充的前端应用&#xff1a;使用 Ant Design Vue 在现代前端开发中&#xff0c;动态表格是一个常见而且非常有用的功能。Ant Design Vue作为一个优秀的UI组件库&#xff0c;为开发者提供了丰富的组件和API来实现复杂的前端需求&#xff0c;包括动态表头和数…

深入探究:Java SE中的数组高级用法

哈喽&#xff0c;各位小伙伴们&#xff0c;你们好呀&#xff0c;我是喵手。运营社区&#xff1a;C站/掘金/腾讯云&#xff1b;欢迎大家常来逛逛 今天我要给大家分享一些自己日常学习到的一些知识点&#xff0c;并以文字的形式跟大家一起交流&#xff0c;互相学习&#xff0c;一…

Rewrite the Stars

文章目录 摘要1、引言2、相关工作3、重写星操作3.1、单层中的星操作3.2、扩展到多层3.3、特殊情况3.4、实证研究3.4.1、星操作的实证优越性3.4.2、决策边界对比3.4.3、扩展到无激活函数的网络 3.5、开放讨论与更广泛的影响 4、概念验证&#xff1a;StarNet4.1、StarNet架构4.2、…