Node.js中有个Fibonacci的异步例子,疑问process.nextTick()作用。

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Node.js中有个Fibonacci的异步例子,疑问process.nextTick()作用。相关的知识,希望对你有一定的参考价值。

就是这个代码(知道上复制就混乱了 = =!)
http://cnodejs.org/topic/50f516fddf9e9fcc585a9b28

我的理解是,先把nextTick中的回调函数在下一次Event loop的时候执行一次而且只执行一次

比如说给参数5进去,也就是说第一次运行fibonacciAsync(5),第二次运行fibonacciAsync(4),第三次循环fibonacciAsync(3),是这样子么?

话说他这是个蛋的异步啊?

这是异步的,要明白nextTick的作用相当于setTimeout(func, 0), 也就是让代码延后一个执行绪,这样子,fibonacci的计算对当前执行绪就不会有任何阻塞了。。。异步的作用就是要解决阻塞的问题
nodejs程序中一般来说总是只有一个线程,要达到非阻塞(异步)的效果,一般就是这样做

举个例子吧:
假设调用方写了这样的代码:
console.log(1);
fibonacciAsync(3, function(result)
console.log (result); //
);
console.log(2);
console.log(3);

fibonacciAsync在被调用后立马就会返回,紧接着console.log(2)执行,console.log(3)执行, 然后才是fibonacciAsync的回调函数被调用
因此程序的结果输出为:
1
2
3
6追问

哦,fibonacci是cpu操作,而console属于I/O是吧?这样的情况好象是异步的,因为CPU和输入输出是两个工作区,可以这样理解吧。

我在想,event loop应该也属于cpu工作区的吧?所以even loop和fibonacci在同一时间只能有一个占有cpu(如果运行完Fibonacci才回even loop,那么这段时间的请求将会失败),nextTick()应该是处理这个问题用的,so,是不是nextTick让cpu每运行完一次event loop只处理一级fibonacci?

求解救。

参考技术A 你运行两个fibonacciAsync()就能看出是异步的了。追问

我又追问了 = = 你看下,谢谢~

追答

nodejs是一个javascript的vm,你不需要考虑cpu什么的。

每一个event loop是一个需要执行的操作的队列,执行完了才执行下一个loop。nextTick就是把一个callback放到下一个loop里。详情可以参考nodejs源码里的src/node.js里面startup.processNextTick这段和src/node.cc里面staticvoidTick(void)到staticHandleNeedTickCallback(constArguments&args)这段。

追问

那就是可以说每个loop里面都只是运行了fabonacciAsync这个运算的一部分而已,对吗?

追答

是的。

本回答被提问者采纳

Node.js 同步与异步

【中文标题】Node.js 同步与异步【英文标题】:Node.js sync vs. async 【发布时间】:2015-02-23 21:11:39 【问题描述】:

我目前正在学习 node.js,我看到了 2 个同步和异步程序示例(同一个)。

我确实了解回调的概念,但我试图了解第二个(异步)示例的好处,因为即使存在这种差异,他们两个似乎也在做完全相同的事情......

您能否详细说明为什么第二个示例会更好? 我很乐意得到更广泛的解释,这将有助于我理解这个概念。

谢谢!!

第一个例子:

var fs = require('fs');

function calculateByteSize() 
    var totalBytes = 0,
        i,
        filenames,
        stats;
    filenames = fs.readdirSync(".");
    for (i = 0; i < filenames.length; i ++) 
        stats = fs.statSync("./" + filenames[i]);
        totalBytes += stats.size;
    
    console.log(totalBytes);


calculateByteSize();

第二个例子:

var fs = require('fs');

var count = 0,
    totalBytes = 0;

function calculateByteSize() 
    fs.readdir(".", function (err, filenames) 
        var i;
        count = filenames.length;

        for (i = 0; i < filenames.length; i++) 
            fs.stat("./" + filenames[i], function (err, stats) 
                totalBytes += stats.size;
                count--;
                if (count === 0) 
                    console.log(totalBytes);
                
            );
        
    );


calculateByteSize();

【问题讨论】:

【参考方案1】:

您的第一个示例是所有阻塞 I/O。换句话说,您需要等到 readdir 操作完成后才能遍历每个文件。然后,您需要阻止(等待)每个单独的同步统计操作运行,然后再转到下一个文件。在所有操作完成之前,calculateByteSize() 调用后不能运行任何代码。

另一方面,异步(第二个)示例使用回调模式是非阻塞的。在这里,只要调用 fs.readdir (但在运行回调之前),执行就会立即返回到 calculateByteSize() 调用之后。一旦 readdir 任务完成,它就会对您的匿名函数执行回调。在这里,它遍历每个文件并再次对 fs.stat 进行非阻塞调用。

第二个更有利。如果您可以假装对 readdir 或 stat 的调用可以在 250 毫秒到 750 毫秒之间完成(这可能不是这种情况),那么您将等待对同步操作的串行调用。但是,异步操作不会导致您在每次调用之间等待。换句话说,遍历 readdir 文件,如果您同步执行,则需要等待每个 stat 操作完成。如果您要异步执行此操作,则不必等待调用每个 fs.stat 调用。

【讨论】:

谢谢!很棒的答案。所以换句话说 - 在第二个例子中,我们可以在收到第一个文件的统计数据之前获得第三个文件的统计数据,对吧? 在哪里可以阅读更多关于幕后发生的事情的信息?如您的回答中所述。 I/O 绑定工作不需要 CPU,因此阻塞等待完成的线程是低效的。 Javascript 在数据准备好时使用事件/回调,允许正在运行的线程利用 CPU 资源。 nodejs.org/en/docs/guides/event-loop-timers-and-nexttick【参考方案2】:

在您的第一个示例中,单线程的 node.js 进程在您的 readdirSync 的整个持续时间内都处于阻塞状态,并且除了等待返回结果之外无法执行任何其他操作。在第二个示例中,进程可以处理其他任务,并且事件循环将在结果可用时将其返回到回调的延续。因此,您可以通过使用异步代码来处理更高的总吞吐量——第一个示例中等待 readdir 所花费的时间可能是实际执行代码所花费时间的数千倍,因此您浪费了 99.9%或更多的 CPU 时间。

【讨论】:

【参考方案3】:

在您的示例中,异步编程的好处确实不太明显。但是假设您的程序还需要做其他事情。请记住,您的 JavaScript 代码在单线程中运行,因此当您选择同步实现时,程序除了等待 IO 操作完成之外不能做任何其他事情。当您使用异步编程时,您的程序可以在 IO 操作在后台(JavaScript 线程之外)运行时执行其他重要任务

【讨论】:

【参考方案4】:

您能否详细说明为什么第二个示例会更好?我很高兴得到更广泛的解释,这将有助于我理解这个概念..

这都是关于网络服务器的并发性(因此得名“节点”)。如果这是在构建脚本中,那么第二个同步示例会“更好”,因为它更直接。并且给定一个磁盘,使其异步可能没有太多实际好处。

但是,在网络服务中,第一个同步版本会阻塞整个过程并破坏节点的主要设计原则。随着并发客户端数量的增加,性能会变慢。然而,第二个异步示例在等待相对较慢的文件系统返回结果时表现相对较好,它可以同时处理所有相对较快的 CPU 操作。异步版本基本上应该能够使您的文件系统饱和,并且无论您的文件系统可以提供多少,节点都能够以该速率将其发送给客户端。

【讨论】:

【参考方案5】:

这里有很多好的答案,但请务必阅读文档:

同步版本将阻塞整个过程,直到它们完成——停止所有连接。

文档中有一个很好的同步与异步概述:http://nodejs.org/api/fs.html#fs_file_system

【讨论】:

以上是关于Node.js中有个Fibonacci的异步例子,疑问process.nextTick()作用。的主要内容,如果未能解决你的问题,请参考以下文章

Node.js 同步与异步

在 Node.js 中等待异步函数返回

Node.js 中的异步函数

白洁血战Node.js并发编程 002 异步

Node.js的循环与异步问题

Node.js回调函数