58

没有人真正问过这个(从我得到的所有“建议”以及在我在这里问之前的搜索中)。

那么为什么 node.js 是异步的呢?

根据我经过一些研究得出的结论:

像 PHP 和 Python 这样的语言是脚本语言(我可能对脚本语言的实际语言有误),而 JavaScript 不是。(我想这是因为 JS 无法编译?)

Node.js 在单个线程上运行,而脚本语言使用多个线程。

异步意味着无状态,并且连接是持久的,而同步则(几乎)相反。

也许在上述某处可以找到答案,但我仍然不确定。

我与该主题相关的第二个也是最后一个问题是:

JavaScript 可以做成同步语言吗?

PS。我知道你们中的一些人会问“为什么要让 JS 同步?” 在你的回答中,但事实是我没有。我只是问这些类型的问题,因为我确信除了我自己之外还有更多的人思考过这些问题。

4

3 回答 3

73

Node.js 在单个线程上运行,而脚本语言使用多个线程。

不是技术上的。Node.js 使用多个线程,但只有一个执行线程。后台线程用于处理 IO 以使所有异步功能正常工作。有效地处理线程是一件非常痛苦的事情,因此下一个最佳选择是在事件循环中运行,这样代码就可以在后台线程被 IO 阻塞时运行。

异步意味着无状态,并且连接是持久的,而同步则(几乎)相反。

不必要。您可以很容易地在异步系统中保存状态。例如,在 Javascript 中,您可以使用bind()将 a 绑定this到函数,从而在函数返回时显式保留状态:

function State() {
    // make sure that whenever doStuff is called it maintains its state
    this.doStuff = this.doStuff.bind(this);
}
State.prototype.doStuff = function () {
};

异步意味着不等待操作完成,而是注册一个监听器。这种情况在其他语言中一直发生,尤其是任何需要接受用户输入的语言。例如,在 Java GUI 中,您不会阻止等待用户按下按钮,而是向 GUI 注册一个侦听器。

我与该主题相关的第二个也是最后一个问题是:

JavaScript 可以做成同步语言吗?

从技术上讲,所有语言都是同步的,甚至是 Javascript。然而,Javascript 在异步设计中工作得更好,因为它被设计为单线程。

基本上有两种类型的程序:

  • CPU 受限 - 让它运行得更快的唯一方法是获得更多的 CPU 时间
  • IO 限制 - 花费大量时间等待数据,因此更快的处理器无关紧要

视频游戏、数字运算器和编译器受 CPU 限制,而 Web 服务器和 GUI 通常受 IO 限制。Javascript 相对较慢(因为它非常复杂),因此它无法在 CPU 绑定场景中竞争(相信我,我已经编写了相当一部分受 CPU 绑定的 Javascript)。

Javascript 不是根据类和对象进行编码,而是根据可以串在一起的简单函数进行编码。这在异步设计中非常有效,因为可以编写算法以在数据进入时增量处理数据。IO(尤其是网络 IO)非常慢,因此数据包之间存在相当长的时间。

例子

假设您有 1000 个实时连接,每个连接每毫秒发送一个数据包,处理每个数据包需要 1 微秒(非常合理)。我们还假设每个连接发送 5 个数据包。

在单线程同步应用程序中,每个连接都将被串行处理。总时间为 (5*1 + 5*.001) * 1000 毫秒,或 ~5005 毫秒。

在单线程异步应用程序中,每个连接都将被并行处理。由于每个数据包需要 1 毫秒,处理每个数据包需要 0.001 毫秒,因此我们可以处理数据包之间的每个连接的数据包,因此我们的公式变为:1000*.001 + 5*1 毫秒,或约 6 毫秒。

这个问题的传统解决方案是创建更多线程。这解决了 IO 问题,但是当连接数增加时,内存使用量(线程消耗大量内存)和 CPU 使用量(将 100 个线程多路复用到 1 个核心比 1 个线程在 1 个核心上更难)也增加了。

但是,也有缺点。如果您的 Web 应用程序碰巧还需要进行一些繁重的数字运算,那么您就是 SOL,因为当您在运算数字时,连接需要等待。线程解决了这个问题,因为当数据准备好等待 IO 的线程时,操作系统可以交换 CPU 密集型任务。此外,node.js 绑定到单核,因此您无法利用多核处理器,除非您启动多个实例和代理请求。

于 2013-07-12T05:43:37.077 回答
36

Javascript 不会编译成任何东西。它在运行时被“评估”,就像 PHP 和 Ruby 一样。因此,它是一种类似于 PHP/Ruby 的脚本语言。(它的正式名称实际上是 ECMAScript)。

Node 遵循的“模型”与 PHP/Ruby 有点不同。Node.js 使用一个“事件循环”(单线程),它的一个目标是接受网络请求并非常快速地处理它们,如果由于某种原因它遇到需要一段时间的操作(API 请求、数据库查询——基本上任何涉及 IO(输入/输出)的东西)它都会将其传递给后台“工作”线程,然后在工作线程等待长任务完成时去做其他事情。当这种情况发生时,主“事件循环”将获取结果并继续处理它们。

PHP/Ruby 遵循线程模型。本质上,对于每个传入的网络请求,应用程序服务器都会启动一个孤立的线程或进程来处理请求。这并不能很好地扩展,与此模型相比,Node 的方法被认为是其核心优势之一。

异步意味着无状态,并且连接是持久的,而同步则(几乎)相反。

不会。同步指令按自然顺序完成,从头到尾。异步指令是指如果程序流程中的某个步骤花费了相对较长的时间,则程序将继续执行操作,并在完成后简单地返回该操作。

JavaScript 可以做成同步语言吗?

JavaScript 中的某些操作是同步的。其他是异步的。例如:


阻塞操作:

for(var k = 0; k < 1; k = k - 1;){
  alert('this will quickly get annoying and the loop will block execution')
alert('this is blocked and will never happen because the above loop is infinite');

异步:

jQuery.get('/foo', function (result) { alert('This will occur 2nd, asynchronously'); });
alert('This will occur 1st. The above operation was skipped over and execution continued until the above operation completes.');
于 2013-07-12T04:35:57.840 回答
25

JavaScript 可以做成同步语言吗?

Javascript 不是“异步语言”;相反,node.js有很多异步API。异步性是 API 而不是语言的属性。在 javascript 中可以轻松地创建和传递函数,这使得传递回调函数变得很方便,这是在异步 API 中处理控制流的一种方式,但javascript没有任何内在的异步。Javascript 可以轻松支持同步 API。

为什么 node.js 是异步的?

Node.js 偏爱异步 API,因为它是单线程的。这允许它有效地管理自己的资源,但要求长时间运行的操作是非阻塞的,并且异步 API 是一种允许通过大量非阻塞操作控制流的方法。

于 2013-07-12T05:25:03.053 回答