iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >怎么用Node.js编写内存效率高的应用程序
  • 858
分享到

怎么用Node.js编写内存效率高的应用程序

2023-06-14 22:06:30 858人浏览 薄情痞子
摘要

这篇文章主要介绍怎么用node.js编写内存效率高的应用程序,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!问题:大文件复制如果有人被要求用 nodejs 写一段文件复制的程序,那么他会迅速写出下面这段代码:const

这篇文章主要介绍怎么用node.js编写内存效率高的应用程序,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!

问题:大文件复制

如果有人被要求用 nodejs 写一段文件复制的程序,那么他会迅速写出下面这段代码:

const fs = require('fs');let fileName = process.argv[2];let destPath = process.argv[3];fs.readFile(fileName, (err, data) => {    if (err) throw err;    fs.writeFile(destPath || 'output', data, (err) => {        if (err) throw err;    });        console.log('New file has been created!');});

这段代码简单地根据输入的文件名和路径,在尝试对文件读取后把它写入目标路径,这对于小文件来说是不成问题的。

现在假设我们有一个大文件(大于4 GB)需要用这段程序来进行备份。就以我的一个达 7.4G 的超高清4K 电影为例子好了,我用上述的程序代码把它从当前目录复制到别的目录。

node basic_copy.js cartoonMovie.mkv ~/Documents/bigMovie.mkv

然后在 ubuntulinux )系统下我得到了这段报错:

/home/shobarani/Workspace/basic_copy.js:7

    if (err) throw err;

             ^

RangeError: File size is greater than possible Buffer: 0x7fffffff bytes

    at FSReqWrap.readFileAfterStat [as oncomplete] (fs.js:453:11)

正如你看到的那样,由于 NodeJS 最大只允许写入 2GB 的数据到它的缓冲区,导致了错误发生在读取文件的过程中。为了解决这个问题,当你在进行 I/O 密集操作的时候(复制、处理、压缩等),最好考虑一下内存的情况。

NodeJS 中的 Streams 和 Buffers

为了解决上述问题,我们需要一个办法把大文件切成许多文件块,同时需要一个数据结构去存放这些文件块。一个 buffer 就是用来存储二进制数据的结构。接下来,我们需要一个读写文件块的方法,而 Streams 则提供了这部分能力。

Buffers(缓冲区)

我们能够利用 Buffer 对象轻松地创建一个 buffer。

let buffer = new Buffer(10); # 10 为 buffer 的体积console.log(buffer); # prints <Buffer 00 00 00 00 00 00 00 00 00 00>

在新版本的 NodeJS (>8)中,你也可以这样写。

let buffer = new Buffer.alloc(10);console.log(buffer); # prints <Buffer 00 00 00 00 00 00 00 00 00 00>

如果我们已经有了一些数据,比如数组或者别的数据集,我们可以为它们创建一个 buffer。

let name = 'Node JS DEV';let buffer = Buffer.from(name);console.log(buffer) # prints <Buffer 4e 6f 64 65 20 4a 53 20 44 45 5>

Buffers 有一些如buffer.toString()和buffer.toJSON()之类的重要方法,能够深入到其所存储的数据当中去。

我们不会为了优化代码而去直接创建原始 buffer。NodeJS 和 V8 引擎在处理 streams 和网络 Socket 的时候就已经在创建内部缓冲区(队列)中实现了这一点。

Streams(流)

简单来说,流就像 NodeJS 对象上的任意门。在计算机网络中,入口是一个输入动作,出口是一个输出动作。我们接下来将继续使用这些术语。

流的类型总共有四种:

  • 可读流(用于读取数据)

  • 可写流(用于写入数据)

  • 双工流(同时可用于读写)

  • 转换流(一种用于处理数据的自定义双工流,如压缩,检查数据等)

下面这句话可以清晰地阐述为什么我们应该使用流。

Stream api (尤其是stream.pipe()方法)的一个重要目标是将数据缓冲限制在可接受的水平,这样不同速度的源和目标就不会阻塞可用内存。

我们需要一些办法去完成任务而不至于压垮系统。这也是我们在文章开头就已经提到过的。

怎么用Node.js编写内存效率高的应用程序

上面的示意图中我们有两个类型的流,分别是可读流和可写流。.pipe()方法是一个非常基本的方法,用于连接可读流和可写流。如果你不明白上面的示意图,也没关系,在看完我们的例子以后,你可以回到示意图这里来,那个时候一切都会显得理所当然。管道是一种引人注目的机制,下面我们用两个例子来说明它。

解法1(简单地使用流来复制文件)

让我们设计一种解法来解决前文中大文件复制的问题。首先我们要创建两个流,然后执行接下来的几个步骤。

监听来自可读流的数据块

把数据块写进可写流

跟踪文件复制的进度

我们把这段代码命名为streams_copy_basic.js

const stream = require('stream');const fs = require('fs');let fileName = process.argv[2];let destPath = process.argv[3];const readabale = fs.createReadStream(fileName);const writeable = fs.createWriteStream(destPath || "output");fs.stat(fileName, (err, stats) => {    this.fileSize = stats.size;    this.counter = 1;    this.fileArray = fileName.split('.');        try {        this.duplicate = destPath + "/" + this.fileArray[0] + '_Copy.' + this.fileArray[1];    } catch(e) {        console.exception('File name is invalid! please pass the proper one');    }        process.stdout.write(`File: ${this.duplicate} is being created:`);        readabale.on('data', (chunk)=> {        let percentageCopied = ((chunk.length * this.counter) / this.fileSize) * 100;        process.stdout.clearLine();  // clear current text        process.stdout.cursorTo(0);        process.stdout.write(`${Math.round(percentageCopied)}%`);        writeable.write(chunk);        this.counter += 1;    });        readabale.on('end', (e) => {        process.stdout.clearLine();  // clear current text        process.stdout.cursorTo(0);        process.stdout.write("Successfully finished the operation");        return;    });        readabale.on('error', (e) => {        console.log("Some error occured: ", e);    });        writeable.on('finish', () => {        console.log("Successfully created the file copy!");    });    });

在这段程序中,我们接收用户传入的两个文件路径(源文件和目标文件),然后创建了两个流,用于把数据块从可读流运到可写流。然后我们定义了一些变量去追踪文件复制的进度,然后输出到控制台(此处为 console)。与此同时我们还订阅了一些事件:

data:当一个数据块被读取时触发

end:当一个数据块被可读流所读取完的时候触发

error:当读取数据块的时候出错时触发

运行这段程序,我们可以成功地完成一个大文件(此处为7.4 G)的复制任务。

$ time node streams_copy_basic.js cartoonMovie.mkv ~/Documents/4kdemo.mkv

然而,当我们通过任务管理器观察程序在运行过程中的内存状况时,依旧有一个问题。

怎么用Node.js编写内存效率高的应用程序

6GB?我们的程序在运行时所消耗的内存,在这里是讲不通的,以及它很有可能会卡死其他的应用程序。

发生了什么?

如果你有仔细观察上图中的读写率,你会发现一些端倪。

Disk Read: 53.4 MiB/s

Disk Write: 14.8 MiB/s

这意味着生产者正在以更快的速度生产,而消费者无法跟上这个速度。计算机为了保存读取的数据块,将多余的数据存储到机器的RAM中。这就是RAM出现峰值的原因。

上述代码在我的机器上运行了3分16秒……

16s user 25.06s system 21% cpu 3:16.61 total

解法2(基于流和自动背压的文件复制)

为了克服上述问题,我们可以修改程序来自动调整磁盘的读写速度。这个机制就是背压。我们不需要做太多,只需将可读流导入可写流即可,NodeJS 会负责背压的工作。

让我们将这个程序命名为streams_copy_efficient.js

const stream = require('stream');const fs = require('fs');let fileName = process.argv[2];let destPath = process.argv[3];const readabale = fs.createReadStream(fileName);const writeable = fs.createWriteStream(destPath || "output");fs.stat(fileName, (err, stats) => {    this.fileSize = stats.size;    this.counter = 1;    this.fileArray = fileName.split('.');        try {        this.duplicate = destPath + "/" + this.fileArray[0] + '_Copy.' + this.fileArray[1];    } catch(e) {        console.exception('File name is invalid! please pass the proper one');    }        process.stdout.write(`File: ${this.duplicate} is being created:`);        readabale.on('data', (chunk) => {        let percentageCopied = ((chunk.length * this.counter) / this.fileSize) * 100;        process.stdout.clearLine();  // clear current text        process.stdout.cursorTo(0);        process.stdout.write(`${Math.round(percentageCopied)}%`);        this.counter += 1;    });        readabale.pipe(writeable); // Auto pilot ON!        // In case if we have an interruption while copying    writeable.on('unpipe', (e) => {        process.stdout.write("Copy has failed!");    });    });

在这个例子中,我们用一句代码替换了之前的数据块写入操作。

readabale.pipe(writeable); // Auto pilot ON!

这里的pipe就是所有魔法发生的原因。它控制了磁盘读写的速度以至于不会阻塞内存(RAM)。

运行一下。

$ time node streams_copy_efficient.js cartoonMovie.mkv ~/Documents/4kdemo.mkv

我们复制了同一个大文件(7.4 GB),让我们来看看内存利用率。

怎么用Node.js编写内存效率高的应用程序

震惊!现在 Node 程序仅仅占用了61.9 MiB 的内存。如果你观察到读写速率的话:

Disk Read: 35.5 MiB/s

Disk Write: 35.5 MiB/s

在任意给定的时间内,因为背压的存在,读写速率得以保持一致。更让人惊喜的是,这段优化后的程序代码整整比之前的快了13秒。

13s user 28.50s system 22% cpu 3:03.35 total

由于 NodeJS 流和管道,内存负载减少了98.68%,执行时间也减少了。这就是为什么管道是一个强大的存在。

9 MiB 是由可读流创建的缓冲区大小。我们还可以使用可读流上的 read 方法为缓冲块分配自定义大小。

const readabale = fs.createReadStream(fileName);readable.read(no_of_bytes_size);

除了本地文件的复制以外,这个技术还可以用于优化许多 I/O 操作的问题:

  • 处理从卡夫卡到数据库的数据流

  • 处理来自文件系统的数据流,动态压缩并写入磁盘

以上是“怎么用Node.js编写内存效率高的应用程序”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注编程网精选频道!

--结束END--

本文标题: 怎么用Node.js编写内存效率高的应用程序

本文链接: https://www.lsjlt.com/news/275649.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 怎么用Node.js编写内存效率高的应用程序
    这篇文章主要介绍怎么用Node.js编写内存效率高的应用程序,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!问题:大文件复制如果有人被要求用 NodeJS 写一段文件复制的程序,那么他会迅速写出下面这段代码:const...
    99+
    2023-06-14
  • 如何用Node.js编写内存效率高的应用程序
    本篇内容介绍了“如何用Node.js编写内存效率高的应用程序”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!...
    99+
    2024-04-02
  • 怎么编写高效的MySQL应用
    这篇文章主要介绍“怎么编写高效的MySQL应用”,在日常操作中,相信很多人在怎么编写高效的MySQL应用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么编写高效的MySQL...
    99+
    2024-04-02
  • Python 中如何编写高效的 Spring 应用程序?
    Python 和 Spring 是两个非常流行的编程语言和框架,它们分别在不同的领域中广泛应用。但是,在某些情况下,我们需要将它们结合起来,以创建高效的应用程序。在本文中,我们将探讨如何使用 Python 编写高效的 Spring 应用程序...
    99+
    2023-08-31
    教程 spring numpy
  • 怎么使用Golang编写高效的存储过程
    这篇“怎么使用Golang编写高效的存储过程”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“怎么使用Golang编写高效的存储...
    99+
    2023-07-05
  • 提升 JavaScript 应用程序效率:内存管理的艺术
    使用严格模式 严格模式有助于防止意外创建全局变量和避免意外修改已声明的变量,这可以减少不必要的内存分配。 限制全局变量 全局变量是存储在全局范围内的变量,可以在代码的任何位置访问。过度使用全局变量会导致内存泄漏,因为它们在不再需要时不会被...
    99+
    2024-04-02
  • 响应式编程与Spring:如何提高Java应用程序的效率?
    随着用户对互联网的需求越来越高,高性能、高并发的 Java 应用程序越来越受到开发者的关注。而响应式编程是一种能够提高应用程序效率的编程范式。本文将介绍什么是响应式编程,为什么要使用它以及如何将其与 Spring 框架结合使用。 一、什么...
    99+
    2023-11-06
    响应 并发 spring
  • 如何使用Node.js开发高效的Web应用程序
    随着互联网的快速发展,面向互联网的应用程序开发成为了众多软件开发领域中的一个重要分支。而Node.js的出现,也使得Web应用程序开发的范式发生了改变。Node.js是一个事件驱动、非阻塞I/O的JavaScript运行环境,这个JavaS...
    99+
    2023-05-14
  • 使用 Node.js WebSocket 打造实时、高效的应用程序
    WebSocket 简介: WebSocket 是一种网络协议,它提供了一种在浏览器和服务器之间建立全双工通信通道的方法。与 HTTP 请求-响应模式不同,WebSocket 允许在客户端和服务器之间持续进行双向通信。这意味着数据可以实时...
    99+
    2024-04-02
  • WebAssembly 与 Node.js:解开高效应用程序的密码
    Wasm 简介 WebAssembly 是一种低级语言,专为在 Web 浏览器中高效执行而设计。它是一种沙盒化的二进制格式,可以编译来自各种语言(如 C、C++ 和 Rust)的代码,并在运行时将它们转换为可移植的机器码。 Node.j...
    99+
    2024-02-19
    WebAssembly Node.js 高效应用程序 跨平台 性能优化
  • 如何使用Go语言编写高效的Apache响应程序?
    Go语言是一种高效的编程语言,它在编写高性能网络应用程序方面具有出色的表现。Apache是一种流行的Web服务器,使用Go语言编写高效的Apache响应程序可以提高Web服务器的性能和响应速度。在本文中,我们将介绍如何使用Go语言编写高效的...
    99+
    2023-11-09
    linux apache 响应
  • 掌握 JavaScript 弱引用:提高应用程序效率
    在 JavaScript 中,弱引用是一种管理内存的方法,它允许对象被回收,即使仍有指向它的引用。这对于提高应用程序的效率和性能至关重要,因为它可以防止内存泄漏和垃圾收集延迟。 理解弱引用 弱引用与强引用不同,强引用会阻止对象被回收,即使...
    99+
    2024-04-02
  • 从算法到存储:使用 Go 和 Bash 编写高效的程序。
    从算法到存储:使用 Go 和 Bash 编写高效的程序 随着计算机科学的不断发展,我们的计算机技能和工具也在不断更新。在这个时代,我们需要编写高效的程序来处理海量的数据,同时还需要保证代码的可维护性和可读性。在本文中,我们将介绍如何使用 G...
    99+
    2023-11-05
    bash 编程算法 存储
  • 分布式接口如何提高PHP应用程序的缓存效率?
    随着互联网的发展,越来越多的应用程序需要处理海量的数据。这就要求我们能够更好地利用缓存来提高应用程序的性能。而分布式接口是一种非常有效的方式,可以帮助我们更好地管理和利用缓存。本文将介绍如何使用分布式接口来提高PHP应用程序的缓存效率。 ...
    99+
    2023-09-06
    缓存 分布式 接口
  • 编写高效的分布式应用程序:Python 异步编程的最佳实践
    Python 是一种流行的编程语言,被广泛应用于各种领域。特别是在分布式应用程序领域,Python 的异步编程模型非常有用。在本文中,我们将探讨 Python 异步编程的最佳实践,以编写高效的分布式应用程序。 什么是异步编程? 在传统的同步...
    99+
    2023-10-15
    异步编程 编程算法 分布式
  • 优化Go语言应用程序的内存使用与垃圾回收效率
    要优化Go语言应用程序的内存使用和垃圾回收效率,可以采取以下几种方法:1. 有效使用内存:减少不必要的内存分配和拷贝操作,尽量使用指...
    99+
    2023-10-08
    Golang
  • 优化Go语言应用程序的内存使用和垃圾回收效率
    要优化Go语言应用程序的内存使用和垃圾回收效率,可以考虑以下几个方面的优化策略:1. 减少内存分配:避免频繁的内存分配和释放操作,可...
    99+
    2023-10-08
    Golang
  • 如何使用Golang编写高效的存储过程
    Golang是一门强大的编程语言,它能够轻松地实现存储过程。在本文中,我们将介绍如何使用Golang编写高效的存储过程,以及在项目中使用它们的好处。一、存储过程的基本概念存储过程是一种预编译的程序,它可以被保存在数据库中并在需要的时候被调用...
    99+
    2023-05-14
    Golang go语言 存储过程
  • ASP.NET Core 能否让你更高效地编写 Web 应用程序?
    ASP.NET Core 是微软推出的一款跨平台、开源、高性能的 Web 应用程序框架。自发布以来,它已经成为了许多开发者的首选框架。本文将探讨 ASP.NET Core 是否能够让你更高效地编写 Web 应用程序。 什么是 ASP.NET...
    99+
    2023-07-10
    leetcode npm linux
  • 怎么使用Golang编写MySQL应用程序
    本篇内容介绍了“怎么使用Golang编写MySQL应用程序”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!步骤一:安装和设置MySQL数据库首...
    99+
    2023-07-05
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作