44

我知道在 node 中开发时,您应该始终尽量避免阻塞(同步)函数并使用异步函数,但是我进行了一些测试以查看它们的比较。

我需要打开一个包含 i18n 数据(如日期和时间格式等)的 json 文件,并将该数据传递给一个类,该类使用该数据在我的视图中格式化数字等。

开始将所有类的方法包装在回调中会有点尴尬,所以如果可能的话,我会改用同步版本。

console.time('one');
console.time('two');
fs.readFile( this.dir + "/" + locale + ".json", function (err, data) {
  if (err) cb( err );
  console.timeEnd('one');
});
var data = fs.readFileSync( this.dir + "/" + locale + ".json" );
console.timeEnd('two');

这会在我的控制台中产生以下几行:

two: 1ms
one: 159ms

似乎 fs.readFileSync 比 fs.readFile 快大约 150 倍,加载一个 50KB 的 json 文件(缩小)大约需要 1 毫秒。我所有的 json 文件都在 50-100KB 左右。

我还在想也许以某种方式将这个 json 数据存储或保存到会话中,以便每个会话(或当用户更改其语言环境时)只读取一次文件。我不完全确定如何做到这一点,这只是一个想法。

可以fs.readFileSync在我的情况下使用还是我以后会遇到麻烦?

4

5 回答 5

75

不,正如您所描述的那样,在节点服务器中使用阻塞 API 调用是不行的。您的站点对许多并发连接的响应将受到巨大影响。这也公然违反了 node.js 的#1 原则。

节点工作的关键在于,它在等待 IO 的同时,也在进行 CPU/内存处理。这需要专门的异步调用。因此,如果您有 100 个客户端读取 100 个 JSON 文件,节点可以要求操作系统读取这 100 个文件,但在等待操作系统返回可用的文件数据时,节点可以处理这 100 个网络请求的其他方面。如果您在那里有一个同步调用,那么在该操作完成时,您的所有客户端处理都会完全停止。因此,当您按顺序读取客户端 1、2、3、4 等的文件时,客户端 100 的连接会等待而不会进行任何处理。这是法尔维尔。

这是另一个类比。如果您去一家餐馆并且是唯一的顾客,那么如果一个人坐在您旁边,接您的订单,烹饪,为您服务并处理账单,您可能会获得更快的服务,而无需与主机打交道的协调开销/女主人、服务员、主厨、排队厨师、收银员等。然而,餐厅有 100 位顾客,额外的协调意味着事情会并行发生,餐厅的整体响应能力将大大提高,远远超过一个人的情况。试图自己处理 100 个客户。

于 2012-12-11T15:42:36.590 回答
12

您正在用同步读取阻塞异步读取的回调,记住单线程。现在我知道时间差仍然是惊人的,但你应该尝试使用一个阅读时间长得多的文件,并想象很多很多客户都会这样做,只有这样开销才会得到回报。那应该回答您的问题,是的,如果您使用阻塞 IO 服务数千个请求,您将遇到麻烦。

于 2012-12-11T15:18:17.897 回答
1

是的,没错,就是在服务端环境中处理异步的方式。但是如果他们的用例不同,比如在客户端 JS 项目中生成构建,同时读写不同风格的 JSON 文件。

影响不大。尽管我们需要一种快速的方式来创建用于部署的缩小构建(这里同步出现)。 了解更多信息和图书馆

于 2019-08-01T08:03:15.223 回答
0

经过大量时间和大量学习和练习后,我再次尝试并找到了答案,我可以举一些例子:

const fs = require('fs');

const syncTest = () => {
    let startTime = +new Date();
    const results = [];
    const files = [];

    for (let i=0, len=4; i<len; i++) {
        files.push(fs.readFileSync(`file-${i}.txt`));
    };

    for (let i=0, len=360; i<len; i++) results.push(Math.sin(i), Math.cos(i));
    console.log(`Sync version: ${+new Date() - startTime}`);
};

const asyncTest = () => {
    let startTime = +new Date();
    const results = [];
    const files = [];

    for (let i=0, len=4; i<len; i++) {
        fs.readFile(`file-${i}.txt`, file => files.push(file));
    };

    for (let i=0, len=360; i<len; i++) results.push(Math.sin(i), Math.cos(i));

    console.log(`Async version: ${+new Date() - startTime}`);
};

syncTest();
asyncTest();
于 2018-10-06T16:54:35.680 回答
-1

我试图检查 fs.readFileSync() 和 fs.readFile() 之间的真实、可测量的速度差异,用于下载 SD 卡上的 3 个不同文件,我在下载之间添加了一些数学计算,但我没有'不明白速度差异在哪里,当节点速度更快时,节点图片上总是显示的速度差异也在简单的操作中,例如下载 3 次相同的文件,并且此操作的时间接近下载 1 次此文件所需的时间.

我知道这无疑是有用的,服务器在下载某些文件期间能够完成其他工作,但是在 youtube 或书籍中有很多时间有一些不精确的图表,因为当你遇到如下情况时异步节点速度较慢然后同步读取小文件(如下所示:85kB、170kB、255kB)。

var fs = require('fs');

var startMeasureTime = () => {
  var start = new Date().getTime();
  return start;
};

// synch version
console.log('Start');
var start = startMeasureTime();

for (var i = 1; i<=3; i++) {
  var fileName = `Lorem-${i}.txt`;
  var fileContents = fs.readFileSync(fileName);
  console.log(`File ${1} was downloaded(${fileContents.length/1000}KB) after ${new Date().getTime() - start}ms from start.`);

  if (i === 1) {
    var hardMath = 3*54/25*35/46*255/34/9*54/25*35/46*255/34/9*54/25*35/46*255/34/9*54/25*35/46*255/34/9*54/25*35/46*255/34/9;  
  };
};

// asynch version
setImmediate(() => {
  console.log('Start');
  var start = startMeasureTime();

  for (var i = 1; i<=3; i++) {
    var fileName = `Lorem-${i}.txt`;
    fs.readFile(fileName, {encoding: 'utf8'}, (err, fileContents) => {
      console.log(`File ${1} was downloaded(${fileContents.length/1000}KB) after ${new Date().getTime() - start}ms from start.`);
    });

    if (i === 1) {
      var hardMath = 3*54/25*35/46*255/34/9*54/25*35/46*255/34/9*54/25*35/46*255/34/9*54/25*35/46*255/34/9*54/25*35/46*255/34/9;  
    };
  };
});

This is from console:
Start
File 1 was downloaded(255.024KB) after 2ms from start.
File 1 was downloaded(170.016KB) after 5ms from start.
File 1 was downloaded(85.008KB) after 6ms from start.
Start
File 1 was downloaded(255.024KB) after 10ms from start.
File 1 was downloaded(85.008KB) after 11ms from start.
File 1 was downloaded(170.016KB) after 12ms from start.
于 2017-10-26T14:23:50.103 回答