【问题标题】:How do I perform operations like read/write to a heavy file in node.js?如何在 node.js 中执行诸如读/写重文件之类的操作?
【发布时间】:2015-10-27 17:15:14
【问题描述】:

我是 node.js 的新手,我想对大文件(通常为 5GB ~ 10GB)执行操作(如读取、写入或存储在数据库中)。
在不影响主线程(UI)的情况下,有哪些可能的方法可以快速完成。我需要实现多线程吗?

我认为由于 I/O 操作是异步的,它永远不会影响主线程。我曾尝试读取一个大文件并将内容写入 HTTPresponse 对象,如下所示 -

var http = require('http'),
fs = require('fs');
fs.readFile('largefile.txt',function(err,data){
    if(err) {
        throw err;
    }
    http.createServer(function(request,response){
        response.writeHead(200,{
            "Content-Type" : "text/plain"
        });
        response.end(data);
    }).listen(8080);
    console.log("server started");
});

largefile.txt 的大小只有 .25GB,运行该程序需要将近 5 分钟。现在实际上,我希望大小为(如前所述)5~10GB,文件类型可以是 .csv,.xls。我该怎么做,请举例说明方法(如果可能的话)。

【问题讨论】:

  • 你为什么要尝试通过一个函数调用将整个 5-10GB 文件读入内存?您可能会导致操作系统级别的磁盘交换。呃,这需要一点时间。您需要一种比这更有效的数据处理策略。最佳策略在很大程度上取决于数据是什么、它在磁盘上的格式以及你试图用它做什么——你都没有透露。
  • 处理磁盘数据的细节与 node.js 无关。这是一个大型数据集的通用编程问题。您必须更具体地了解数据是什么以及您要如何处理这些数据。例如,如果您想将多行 CSV 格式的信息放入数据库,那么您应该一次读取一行,解析它,将其写入数据库,获取下一行等等。有流对象可以为您逐行处理数据。有些数据库具有用于存储数据的接口。
  • 而且,是的,如果是 10GB 的数据,那么在任何编程环境中,读取这么大的 CSV 文件并将每一行写入数据库都将花费大量时间。如果都是异步 I/O,那么您的节点服务器可以交错执行其他操作,但编写一个独立的 node.js 程序可能更容易,您可以将其作为子进程启动以使用您的大数据文件并将其放入在数据库中。这样你就有多个 CPU 工作,你的主服务器线程受到的影响就会更小。
  • Node.js 非阻塞并不意味着您不会占用主线程的处理时间。 Node.js 是单线程的,所以异步操作默认是线程安全的,因为只有一个线程。但是,在同一线程上运行的每个异步操作仍然可以轮到并分配时间在该轮次中工作,因此长时间运行的异步操作将占用其他尝试完成自己工作的操作。将繁重的工作委托给专用线程(在这种情况下是另一个 node.js 进程)是通常的解决方案。
  • 这个问题中的信息确实仍然不足,无法给出有意义的答案。选择读取巨型文件并将其放入数据库的策略取决于文件中的数据类型、您对数据执行的操作、正在使用的数据库、需要执行的频率、其余部分的繁忙程度您的服务器进程是等等......处理任何语言的大型数据文件是一项特殊的专业知识,无法在 StackOverflow 上的一个答案中完全解释。

标签: node.js multithreading io


【解决方案1】:

从磁盘读取到工作程序内存非常慢。这是硬件限制。

如果文件是 CSV(由换行符分隔的逗号分隔值),您可能希望逐行读取它,或者搜索正确的行然后读取,而不是将整个文件读入内存然后打印整个事情了。如果您逐行阅读,至少您正在更新正在阅读的内容。

首先,您可以使用fs.read 而不是fs.readFile 逐字符读取文件,寻找换行符。

但快速搜索“nodejs 读取文件行”显示有许多其他方法可以使用 Node 来解决此问题。

编辑:

我还不能评论,但是关于子进程,正如 jfriend00 和 SirDemon 所说,虽然 NodeJS 使用非阻塞 IO(将磁盘读取到内存不会阻塞代码)并且它通常是面向事件/异步的设计(执行可能会在等待时在代码段之间交换)代码仅在单个 CPU 上单线程运行(代码仍会阻塞代码)。因此,子进程允许您使用另一个 CPU。它都是为动态服务器设计的,因此您几乎可以一直运行代码并读取文件,但无需为每个文件读取维护一个新线程/进程(服务器通常使用线程池)的开销。 (我认为这是正确的?)

【讨论】:

    猜你喜欢
    • 2021-07-06
    • 2011-08-16
    • 2011-11-21
    • 1970-01-01
    • 2017-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多