javascript - Node.js process.exit()无法完全退出,并且存在异步fs.writeFile的危险

标签 javascript node.js file

tl;博士:

从异步事件(甚至可能只是从一个普通的旧循环)调用异步fs.writeFile,然后调用process.exit()成功打开文件,但无法将数据刷新到文件中。给writeFile的回调没有机会在进程退出之前运行。这是预期的行为吗?

不管process.exit()是否未能执行此清理,我都质疑至少应尝试将文件写入调度表是否应由 Node 负责,因为很可能情况是大缓冲区的重新分配取决于将它们写到磁盘上。

细节

我有一个概念上很基本的node.js代码,可以对大型数据文件进行转换。这恰好是LiDAR传感器的数据文件,应该不相关。由于其存在的性质,它只是一个非常大的数据集。它在结构上很简单。传感器通过网络发送其数据。这个脚本的任务是为每个旋转扫描生成一个单独的文件。该逻辑的细节也不重要。

基本思想是,我使用node_pcap来读取巨大的.pcap文件,该文件使用由node_pcap给出的用于执行此任务的方法,即“离线模式”。

这意味着,与其“异步捕获”网络数据包,不如说是“生成”了代表数据包的相当密集的异步事件流。

因此,程序的主要结构由一些全局状态变量和对pcap session 的单个回调组成。我初始化全局变量,然后将回调函数分配给pcap session 。此packet事件的回调完成所有工作。

这项工作的一部分是写出大量数据文件。有时数据包会指示某些情况,这意味着我应该继续写入下一个数据文件。我增加了数据文件名索引,并再次调用fs.writeFile()开始写入新文件。由于我只是在写作,因此让 Node 决定何时开始写作是很自然的事情。

基本上,fs.writeFileSyncfs.writeFile都应该最终以异步方式在其各自的文件上调用OS的write()系统调用。这不会打扰我,因为我只是在写东西,所以写的异步性质可能会影响某些访问模式,这对我来说并不重要,因为我不进行任何访问。唯一的不同在于,writeFileSync强制阻塞 Node 事件循环,直到write()系统调用完成为止。

随着程序的进行,当我使用writeFile(js异步版本)时,会创建数百个输出文件,但没有任何数据写入其中。不是一个。创建第一百个数据文件时,第一个数据文件仍处于打开状态。

从概念上讲这很好。原因是 Node 忙于处理新数据,并高兴地坚持使用越来越多的文件描述符,最终将这些描述符写入文件中。同时,它还必须将内存中的所有内容保存在内存中。文件的最终内容。这最终会用完,但让我们暂时忽略RAM大小限制。显然,这里发生的一件坏事将是RAM耗尽,并使程序崩溃。希望 Node 会很聪明,并意识到它只需要计划一些文件写入,然后就可以释放一堆缓冲区了。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

如果我在所有这些语句中添加一条语句来调用process.exit(),我希望该 Node 将在退出之前清理并刷新待处理的writeFile写入。

但是 Node 不这样做。

更改为writeFileSync显然可以解决该问题。
更改和 chop 我的输入数据,使得未显式调用process.exit()也会导致在输入事件完成泵送的最后最终写入文件(并给writeFile提供了完成回调)。

这似乎向我表明process.exit()不正确地执行了清理。

问题:除了在中间完全退出事件循环之外,还有别的选择吗?注意我必须手动 chop 我的大型输入文件,因为以process.exit()终止会导致所有文件写入均未完成。

这是 Node v0.10.26不久前通过Homebrew在OS X上安装的。

继续我的思考过程,我在这里看到的行为使人们质疑使用writeFile的基本目的。它应该进行改进,以便在 Node 认为合适的时候可以灵活地写入我的文件。但是,显然,如果 Node 的事件循环被足够强力地泵入,那么它将基本上“落后于”其工作负载。

就像事件循环有一个收件箱和一个发件箱一样。以此类推,发件箱代表包含我正在写入文件的数据的临时变量。像我这样的懒惰高效的程序员想要做出的假设是,收件箱和发件箱是我可以使用的接口(interface),并且它们是灵活的,并且系统将为我管理。但是,如果我以过高的速度喂入收件箱,则 Node 实际上无法跟上进度,它只会开始将数据堆积到发件箱中而没有任何时间刷新它,因为出于某种原因或其他原因,调度是这样的必须首先处理所有传入事件。反过来,这延迟了发件箱内容的所有垃圾回收,并且很快我们就耗尽了系统的RAM。当在复杂的系统中使用此模式时,这是很容易发现的错误。我很高兴我对这个项目采取了模块化的方法。

我的意思是,是的,显然,显然,毫无疑问,答案是使用writeFileSync,就像我几乎每次使用node编写文件一样。

那么,即使拥有writeFile的值又是多少呢?在这一点上,我正在交换并行处理方面的潜在小幅增长,​​以增加以下可能性:如果(由于某种原因)计算机的处理能力下降(无论是热节流还是操作系统级别调度,或者我不按时支付IaaS账单,或其他任何原因),是否有可能导致滚雪球般的内存爆炸?

也许这正成为解决流数据处理系统固有的真正相当复杂的问题的核心,而且我不能现实地期望这种基于事件的处理模型能够逐步提高并自动优雅地解决这些问题。也许我应该感到满意,因为它只能使我走近一半的路来获得强大的功能。也许我只是在上面表达自己的愿望,并且认为 Node 需要较少确定性地“改善”其事件循环的调度对我来说是不合理的。

最佳答案

我不是 Node 专家,但似乎可以使用流简化您的问题。流使您可以暂停和继续,还可以提供其他简洁功能。我建议您看一下Pedro Teixeira撰写的Professional NodeJS的第9章。您可以轻松地找到在线副本以进行阅读。它提供了有关如何使用流读取和写入数据以及如何防止潜在的内存泄漏和数据丢失的非常详细且说明充分的示例。

关于javascript - Node.js process.exit()无法完全退出,并且存在异步fs.writeFile的危险,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24445791/

相关文章:

node.js - 如何在nodejs中上传根文件夹之外的文件?

javascript - 将表单数据写入 json 文件 - javascript

file - 无法访问 bundle 资源/文件 (OSGi)

node.js - 如何从node.js中的目录获取所有文件路径

file - flutter 将文件保存在本地,以便在 Files App 中可用

javascript - 是否可以异步执行 gm_xmlhttprequest?

javascript - 在 javascript 中解析 JSON 对象(键/值对)

javascript - 如何在不更改坐标的情况下转换(旋转)svg 文本元素?

javascript - 将字符串作为变量传递时,Array.indexOf() 找不到值?

javascript - ng-submit 不起作用