Node.js 单线程同步和异步混淆
假设Node.js 单线程同步和异步混淆,node.js,asynchronous,Node.js,Asynchronous,假设makeBurger()需要10秒 在同步程序中 function serveBurger() { makeBurger(); makeBurger(); console.log("READY") // Assume takes 5 seconds to log. } 执行此操作总共需要25秒 因此,对于NodeJs,假设我们制作了一个异步版本的makeBurgerAsync(),这也需要10秒 function serveBurger() { makeBurge
makeBurger()
需要10秒
在同步程序中
function serveBurger() {
makeBurger();
makeBurger();
console.log("READY") // Assume takes 5 seconds to log.
}
执行此操作总共需要25秒
因此,对于NodeJs,假设我们制作了一个异步版本的makeBurgerAsync()
,这也需要10秒
function serveBurger() {
makeBurgerAsync(function(count) {
});
makeBurgerAsync(function(count) {
});
console.log("READY") // Assume takes 5 seconds to log.
}
因为它是单线程。我无法想象幕后到底发生了什么
console.log(“READY”)
将立即执行李>
console.log(“READY”)
时,两个异步函数都没有真正完成工作,对吗?因为单线程占用console.log 5秒钟李>
function makeBurger() {
var count = 0;
count++; // 1 time
...
count++; // 999999 times
return count;
}
function makeBurgerAsync(callback) {
var count = 0;
count++; // 1 time
...
count++; // 999999 times
callback(count);
}
在node.js中,所有异步操作都在node.js Javascript单线程之外完成任务。它们要么使用本机代码线程(如node.js中的磁盘I/O),要么根本不使用线程(如事件驱动网络或计时器) 您不能完全采用node.js Javascript编写的同步操作,而神奇地使其异步。异步操作是异步的,因为它调用一些用本机代码实现并以实际异步方式编写的函数。因此,要使某些东西异步,必须专门编写以使用低级别操作,这些操作本身与异步本机代码实现是异步的 这些带外操作,然后通过事件队列与主node.js Javascript线程通信。当其中一个异步操作完成时,它会将一个事件添加到Javascript事件队列中,然后当单node.js线程完成当前正在执行的操作时,它会从事件队列中获取下一个事件并调用与该事件关联的回调 因此,可以并行运行多个异步操作。并行运行3个操作通常比顺序运行相同的3个操作具有更短的端到端运行时间 让我们检查一个真实的异步情况,而不是您的伪代码:
function doSomething() {
fs.readFile(fname, function(err, data) {
console.log("file read");
});
setTimeout(function() {
console.log("timer fired");
}, 100);
http.get(someUrl, function(err, response, body) {
console.log("http get finished");
});
console.log("READY");
}
doSomething();
console.log("AFTER");
下面是逐步发生的情况:
fs.readFile()
已启动。由于node.js使用线程池实现文件I/O,因此此操作将传递给node.js中的一个线程,并将在单独的线程中运行fs.readFile()
完成,即可调用setTimeout()
。这使用libuv(node.js构建的跨平台库)中的计时器子系统。这也是非阻塞的,因此计时器被注册,然后继续执行console.log(“就绪”)
将运行setTimeout()
首先完成。完成后,node.js中的一些内部构件将在事件队列中插入一个事件,其中包含计时器事件和已注册的回调。当node.js主js线程执行完任何其他js后,它将从事件队列中抓取下一个事件,并调用与其关联的回调fs.readFile()
操作完成。使用自己的线程,它将在node.js事件队列中插入一个事件setTimeout()
回调完成。此时,JS解释器将检查事件队列中是否有其他事件。fs.readfile()
事件位于队列中,因此它将获取该事件并调用与该事件关联的回调。该回调执行并完成http.get()
操作完成。在node.js内部,事件被添加到事件队列中。由于事件队列中没有其他内容,并且JS解释器当前没有执行,因此可以立即为该事件提供服务,并且可以调用http.get()
的回调READY
AFTER
timer fired
file read
http get finished
请记住,这里最后三行的顺序是不确定的(它只是基于不可预测的执行速度),因此这里的精确顺序只是一个示例。如果您需要按照特定的顺序执行这些代码,或者需要知道这三个代码是何时完成的,那么您必须添加额外的代码来跟踪这些代码
既然您试图通过使某些当前不异步的东西异步化来加快代码的运行速度,那么让我重复一遍。您不能完全使用Javascript编写同步操作并“使其异步”。您必须从头开始重写它,以使用根本不同的异步低级操作,或者您必须将其传递给其他进程执行,然后在执行时收到通知