node.js 如何调度异步和同步任务?

鲁帕姆·科凯塔

我知道node.js如何通过使用事件循环来调度异步任务来异步执行代码而不阻塞执行主线程,但我不清楚主线程实际上是如何决定为异步搁置一段代码的执行。

基本上是什么表明这段代码应该异步执行而不是同步执行,区别因素是什么?

还有,node提供的异步和同步API有哪些?

磨人

当您询问时,您的假设存在错误:

什么表明这段代码应该异步执行而不是同步执行

错误是认为某些代码是异步执行的。这不是真的。

Javascript(包括 node.js)同步执行所有代码您的代码中没有任何部分是异步执行的。

因此,乍一看,这就是您问题的答案:不存在异步代码执行之类的东西。

等等,什么?

但是所有异步的东西呢?

就像我说的,node.js(和一般的 javascript)同步执行所有代码。然而,javascript 能够异步等待某些事件没有异步代码执行,但是有异步等待。

代码执行和等待有什么区别?

让我们看一个例子。为了清楚起见,我将使用伪语言中的伪代码来消除 javascript 语法中的任何混淆。假设我们要从文件中读取。这种假语言支持同步和异步等待:

示例 1。同步等待驱动器从文件中返回字节

data = readSync('filename.txt');
// the line above will pause the execution of code until all the
// bytes have been read

例 2。异步等待驱动器从文件中返回字节

// Since it is asynchronous we don't want the read function to 
// pause the execution of code. Therefore we cannot return the
// data. We need a mechanism to accept the returned value.

// However, unlike javascript, this fake language does not support
// first-class functions. You cannot pass functions as arguments
// to other functions. However, like Java and C++ we can pass
// objects to functions

class MyFileReaderHandler inherits FileReaderHandler {
    method callback (data) {
        // process file data in here!
    }
}

myHandler = new MyFileReaderHandler()

asyncRead('filename.txt', myHandler);
// The function above does not wait for the file read to complete
// but instead returns immediately and allows other code to execute.
// At some point in the future when it finishes reading all data
// it will call the myHandler.callback() function passing it the
// bytes form the file.

如您所见,异步 I/O 对 javascript 来说并不特殊。它早在 C++ 中的 javascript 甚至处理文件 I/O、网络 I/O 和 GUI 编程的 C 库之前就已经存在。事实上,它甚至在 C 之前就已经存在。您可以在汇编中执行这种逻辑(实际上这就是人们设计操作系统的方式)。

javascript 的特别之处在于,由于它的函数性质(一等函数),传递一些您希望在未来执行的代码的语法更简单:

asyncRead('filename.txt', (data) => {
    // process data in here
});

或者在现代 javascript 中甚至可以看起来像同步代码:

async function main () {
    data = await asyncReadPromise('filename.txt');
}

main();

等待和执行代码有什么区别。您不需要代码来检查事件吗?

实际上,您需要 0% 的 CPU 时间来等待事件。您只需要执行一些代码来注册一些中断处理程序,当中断发生时,CPU硬件(而不是软件)将调用您的中断处理程序。各种硬件都被设计用来触发中断:键盘、硬盘、网卡、USB 设备、PCI 设备等。

磁盘和网络 I/O 效率更高,因为它们也使用 DMA。这些是硬件内存读取器/写入器,可以将大块(千字节/兆字节)内存从一个地方(例如硬盘)复制到另一个地方(例如 RAM)。CPU 实际上只需要设置DMA 控制器,然后就可以自由地做其他事情了。一旦 DMA 控制器完成传输,它将触发一个中断,该中断将执行一些设备驱动程序代码,该代码将通知操作系统某些 I/O 事件已完成,这将通知 node.js 将执行您的回调或履行您的 Promise。

以上所有使用专用硬件而不是在CPU上执行指令来传输数据。因此等待数据占用 0% 的 CPU 时间。

因此,node.js 中的并行性与您的 CPU 支持多少 PCIe 通道有关,而不是它拥有多少 CPU 内核。

如果愿意,您可以异步执行 javascript

与任何其他语言一样,现代 javascript以浏览器中的webworkers和node.js中的worker_threads形式提供多线程支持。但这是常规的多线程,就像您故意启动另一个线程以异步执行代码的任何其他语言一样。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章