node.js fs.readFileSync 似乎比 fs.readFile 更快 - 可以用于生产中的 Web 应用程序吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13822085/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
fs.readFileSync seems faster than fs.readFile - is it OK to use for a web app in production?
提问by ragulka
I know that when developing in node, you should always try to avoid blocking (sync) functions and go with async functions, however I a little test to see how they compare.
我知道在 node 中开发时,您应该始终尝试避免阻塞(同步)函数并使用异步函数,但是我进行了一些测试以了解它们的比较情况。
I need to open a json file that contains i18n data (like date and time formats, etc) and pass that data to a class that uses this data to format numbers etc in my views.
我需要打开一个包含 i18n 数据(如日期和时间格式等)的 json 文件,并将该数据传递给一个类,该类使用此数据在我的视图中格式化数字等。
It would be kind of awkward to start wrapping all the class's methods inside callbacks, so if possible, I would use the synchronous version instead.
开始将所有类的方法包装在回调中会有点尴尬,所以如果可能的话,我会改用同步版本。
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');
This results in the following lines in my console:
这会在我的控制台中产生以下几行:
two: 1ms
one: 159ms
It seems that fs.readFileSync is about 150 times faster than fs.readFile and takes about 1ms to load a 50KB json file (minified). All my json files are around 50-100KB.
似乎 fs.readFileSync 比 fs.readFile 快大约 150 倍,并且需要大约 1ms 来加载 50KB json 文件(缩小)。我所有的 json 文件都在 50-100KB 左右。
I was thinking also maybe somehow memoizing or saving this json data to session so that the file is read only once per session (or when the user changes their locale). I'm not entirely sure how to do that, it's just an idea.
我也在想也许以某种方式记住或保存这个 json 数据到会话,以便每个会话只读取一次文件(或当用户更改他们的语言环境时)。我不完全确定如何做到这一点,这只是一个想法。
Is it okay to use fs.readFileSyncin my case or will I get in trouble later?
可以fs.readFileSync在我的情况下使用吗,否则我以后会遇到麻烦吗?
回答by Peter Lyons
No, it is not OK to use a blocking API call in a node server as you describe. Your site's responsiveness to many concurrent connections will take a huge hit. It's also just blatantly violating the #1 principle of node.
不,正如您所描述的那样,在节点服务器中使用阻塞 API 调用是不行的。您的站点对许多并发连接的响应能力将受到巨大影响。它也只是公然违反了 node.js 的 #1 原则。
The key to node working is that while it is waiting on IO, it is doing CPU/memory processing at the same time. This requires asynchronous calls exclusively. So if you have 100 clients reading 100 JSON files, node can ask the OS to read those 100 files but while waiting for the OS to return the file data when it is available, node can be processing other aspects of those 100 network requests. If you have a single synchronous call in there, ALL of your client processing stops entirely while that operation completes. So client number 100's connection waits with no processing whatsoever while you read files for client 1, 2, 3 , 4 and so on sequentially. This is Failville.
节点工作的关键在于,它在等待 IO 的同时,也在进行 CPU/内存处理。这需要专门的异步调用。因此,如果您有 100 个客户端读取 100 个 JSON 文件,节点可以要求操作系统读取这 100 个文件,但是在等待操作系统返回可用文件数据时,节点可以处理这 100 个网络请求的其他方面。如果您在那里有一个同步调用,则在该操作完成时,您的所有客户端处理都将完全停止。因此,当您按顺序读取客户端 1、2、3、4 等的文件时,客户端编号 100 的连接将等待而不进行任何处理。这是法尔维尔。
Here's another analogy. If you went to a restaurant and were the only customer, you would probably get faster service if a single person sat you, took your order, cooked it, served it to you, and handled the bill without the coordination overhead of dealing with host/hostess, server, head chef, line cooks, cashiers, etc. However, with 100 customers in the restaurant, the extra coordination means things happen in parallel and overall responsiveness of the restaurant is increased way beyond what it would be if a single person was trying to handle 100 customers on their own.
这是另一个类比。如果你去了一家餐馆并且是唯一的顾客,如果一个人坐在你身边,接受你的订单,做饭,给你上菜,然后处理账单,你可能会得到更快的服务,而无需与主人打交道的协调开销/女主人、服务员、主厨、厨师、收银员等。 然而,餐厅有 100 名顾客,额外的协调意味着事情同时发生,餐厅的整体响应能力提高,远远超出了一个人的情况试图自己处理 100 个客户。
回答by lab419
You are blocking the callback of the asynchronous read with your synchronous read, remember single thread. Now I understand that the time difference is still amazing, but you should try with a file that is much, much longer to read and imagine that many, many clients will do the same, only then the overhead will pay off. That should answer your question, yes you will run into trouble if you are serving thousands of requests with blocking IO.
您正在使用同步读取阻止异步读取的回调,请记住单线程。现在我明白时差仍然很惊人,但你应该尝试使用一个阅读时间长得多的文件,并想象很多很多客户端会做同样的事情,只有这样开销才会得到回报。这应该可以回答您的问题,是的,如果您通过阻塞 IO 来处理数千个请求,您会遇到麻烦。
回答by buuuudzik
After a lot of time and a lot of learn & practice I've tried once more and I've found the answer and I can show some example:
经过大量时间和大量学习与实践,我再次尝试并找到了答案,我可以展示一些示例:
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();
回答by Anupam Maurya
Yes, it's correct, to deal with the asynchronous way in a server-side environment. But if their use case is different like to generating the build as in client-side JS project, meanwhile reading and writing the JSON files for different flavors.
是的,在服务器端环境中处理异步方式是正确的。但是如果他们的用例不同,比如在客户端 JS 项目中生成构建,同时读取和写入不同风格的 JSON 文件。
It doesn't affect that much. Although we needed a rapid manner to create a minified build for deployment (here synchronous comes into the picture). for more info and library
它没有那么大的影响。尽管我们需要一种快速的方式来创建一个用于部署的缩小版本(这里是同步的)。 欲了解更多信息和图书馆
回答by buuuudzik
I've tried to check the real, measurable difference in a speed between fs.readFileSync() and fs.readFile() for downloading 3 different files which are on SD card and I've added between this downloads some math calculation and I don't understand where is the difference in speed which is always showed on node pictures when node is faster also in simple operation like downloading 3 times the same file and the time for this operation is close to time which is needed for downloading 1 time this file.
我试图检查 fs.readFileSync() 和 fs.readFile() 下载 SD 卡上 3 个不同文件的速度之间真实的、可测量的差异,我在这些下载之间添加了一些数学计算,但我没有'不明白当节点更快时节点图片上总是显示的速度差异在简单的操作中,例如下载3次相同的文件并且此操作的时间接近下载1次此文件所需的时间.
I understand that this is no doubtly useful that server during downloading some file is able to doing other job but a lot of time on youtube or in books there are some diagrams which are not precise because when you have a situation like below async node is slower then sync in reading small files(like below: 85kB, 170kB, 255kB).
我知道这无疑是有用的,服务器在下载某些文件期间能够做其他工作,但是在 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 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 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.

