多线程:事件循环与线程池等等……
😩 每当我们想到运行程序时,我们总是专注于运行代码,但我们并不关心是谁在运行代码。
你知道是谁运行代码,是谁将程序送入内存以及程序是如何执行的吗?
😎 所以,有一种叫做线程的东西。它负责使用主内存(RAM)、CPU和存储空间,或者更广泛地说,使用我们机器的资源来运行你的程序/代码。
线程只不过是一个拥有线程块、堆栈和堆访问权限的工作进程。
但是栈、堆和线程块到底是什么?
📌 栈、堆、线程块
- 每当你编写一个函数时
def add(a, b):
return a+b
然后,当我们运行这段代码时,我们会在主内存(RAM)中声明该函数,并将指向该函数的指针存储在堆栈中。

图片参考:-链接
✨ 因此,栈是作用域级别的内存空间,用于存储像 a 和 b 这样的局部变量;而堆是动态内存,用于存储指针、动态数组和对象(类的实例)。
📌 当函数执行完毕时,栈会被清空,就像被刷新一样;但堆在某些编程语言中需要手动清理,而在另一些编程语言中则有垃圾回收机制。
别担心,跟着做你肯定能学会,请点赞并保存这篇文章以支持我们。
😎 现在,我们了解了栈和堆,它们用于在程序运行时存储动态数据。
但是我们这位能扛起整件东西的家伙呢?(帖子内容正确)
所以,线程有线程块。
因此,线程块包含一些字段和一个存储单元,其中包含运行程序所需的信息,并用于访问共享空间或自身空间。共享空间指的是堆内存空间,而自身空间指的是栈内存空间。
💀接下来,我们将介绍什么是事件循环和线程池。
如果有人使用 JavaScript 工作,他/她可能知道 JavaScript 是一种单线程语言,这意味着无论你的代码是什么,它都将由单个工作线程执行。
但是,如果有人使用 Java、C、C++ 等编程语言,我们可以并行使用多个线程。
各位耐心点,你们会明白的💯
📌 多线程
假设你有两个函数(用JAVA编写)
class Main{
public void static main(String[] args){
System.out.println("Hello world");
}
public static void add(int a, int b){
System.out.println(a+b);
}
public static void substract(int a, int b){
System.out.println(a-b);
}
}
😎 现在,线程 1 可以执行 add() 函数并开始执行,线程 2 可以执行 substract() 函数并开始执行,对吗?因为它们是相互独立的。
所以,这里存在一种叫做上下文切换的机制。比如说,如果线程 1 正在等待用户输入,那么线程 2 就会运行,上下文就会从线程 1 切换到线程 2。
😎 线程 1 的当前状态将被存储在其代码块中,线程 2 将继续运行。多线程的主要目的是确保 CPU 不会进入空闲状态,而是持续处于使用状态。
😩 但是在 Javascript 中我们只有一个线程,如何才能实现并行化呢?
🫶 这里是事件循环。
📌 事件循环 vs 线程池
假设JS代码如下:
function add(){
setTimeout(()->{
console.log("I am lazy");
}, 1000);
console.log("I am active");
}
这里我们可以看到有一个代码块正在等待 1000 毫秒(1 秒),之后才会执行。但还有其他独立的代码行可以同时运行。所以,
setTimeout(()->{
console.log("I am lazy");
}, 1000);
可以进入等待阶段,与此同时
console.log("I am active");
可以运行。因此,setTimeout() 函数会放在事件循环中,等待同步代码运行完毕。而这段等待的代码是异步代码。

图片参考:-链接
❤️ 在这里,事件循环会不断循环,并检查回调队列中是否有需要运行的程序(异步代码会进入这个队列)。所有同步代码执行完毕后(当同步代码栈为空时),异步代码才会运行。
😩 这算是一种阻塞机制吧?如果同步代码陷入无限循环,所有异步代码都会停止运行,对吧?没错,这就是问题所在,所以超时机制需要仔细配置。
现在,我们来看一下线程池:
🥹 现在的问题是,当我们读取一个大文件并将其设为异步操作时,如果异步代码将来也要运行,那么其他同步代码是如何运行的?
这里就是线程池的用武之地。例如,要读取一个文件,你会这样做。
let filePath = "test.txt";
let fileContent = fs.readFile(filePath, "utf-8", (data, err)->{
return data;
})
现在,我们的操作系统有线程,JavaScript 会将读取文件的任务分配给操作系统线程池中的一个线程,而我们的操作系统有一些系统调用,它会使用这些调用来读取文件并将其保存到缓冲区中。
此缓冲区仅存在于内存中。
byte[] buff;
而且还有一个回调函数
(data, err)->{
return data;
}
文件读取完成后,该函数将被调用。然后,JavaScript 主线程会将 buff[] 中的内容复制到 data 数组中。
所以,在JS中,一切看起来都是并行的,但实际上并非如此。
🔥 今天就到这里。我们学习了……
- 线程、栈、堆
- 线程块
- 多线程,上下文切换
- 事件循环,线程池
关注我们,获取更多深度文章🫶
访问我的 YouTube 频道了解更多信息:链接[语言:印地语,印度🇮🇳]
文章来源:https://dev.to/singhdevhub/multithreading-event-loops-vs-thread-pools-and-more-48di





