首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >将大数组传递给节点子进程

将大数组传递给节点子进程
EN

Stack Overflow用户
提问于 2017-05-19 00:12:35
回答 6查看 8.8K关注 0票数 27

我想在大型阵列上执行复杂的CPU密集型工作。理想情况下,我希望将其传递给子进程。

代码语言:javascript
复制
var spawn = require('child_process').spawn;

// dataAsNumbers is a large 2D array
var child = spawn(process.execPath, ['/child_process_scripts/getStatistics', dataAsNumbers]);

child.stdout.on('data', function(data){
  console.log('from child: ', data.toString());
});

但是当我这样做时,node给出了错误:

衍生E2BIG

我偶然发现了this article

因此,通过管道将数据传送子进程似乎是可行的。我的代码现在是:

代码语言:javascript
复制
var spawn = require('child_process').spawn;

console.log('creating child........................');

var options = { stdio: [null, null, null, 'pipe'] };
var args = [ '/getStatistics' ];
var child = spawn(process.execPath, args, options);

var pipe = child.stdio[3];

pipe.write(Buffer('awesome'));

child.stdout.on('data', function(data){
  console.log('from child: ', data.toString());
});

然后在getStatistics.js中:

代码语言:javascript
复制
console.log('im inside child');

process.stdin.on('data', function(data) {
  console.log('data is ', data);
  process.exit(0);
});

但是,process.stdin.on中的回调并未到达。如何在我的子脚本中接收流?

编辑

我不得不放弃缓冲方法。现在我将数组作为一条消息发送:

代码语言:javascript
复制
var cp = require('child_process');
var child = cp.fork('/getStatistics.js');

child.send({ 
  dataAsNumbers: dataAsNumbers
});

但这仅在dataAsNumbers长度小于20,000时有效,否则它会超时。

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2017-05-21 06:01:16

有了如此大量的数据,我会考虑使用,而不是将数据复制到子进程中(这就是使用管道或传递消息时发生的情况)。这将节省内存,为父进程占用更少的CPU时间,并且不太可能遇到某些限制。

shm-typed-array是一个非常简单的模块,似乎适合您的应用程序。示例:

parent.js

代码语言:javascript
复制
"use strict";

const shm = require('shm-typed-array');
const fork = require('child_process').fork;

// Create shared memory
const SIZE = 20000000;
const data = shm.create(SIZE, 'Float64Array');

// Fill with dummy data
Array.prototype.fill.call(data, 1);

// Spawn child, set up communication, and give shared memory
const child = fork("child.js");
child.on('message', sum => {
    console.log(`Got answer: ${sum}`);

    // Demo only; ideally you'd re-use the same child
    child.kill();
});
child.send(data.key);

child.js

代码语言:javascript
复制
"use strict";

const shm = require('shm-typed-array');

process.on('message', key => {
    // Get access to shared memory
    const data = shm.get(key, 'Float64Array');

    // Perform processing
    const sum = Array.prototype.reduce.call(data, (a, b) => a + b, 0);

    // Return processed data
    process.send(sum);
});

请注意,我们只通过IPC从父进程向子进程发送一个小的“键”,而不是整个数据。因此,我们节省了大量的内存和时间。

当然,您可以将'Float64Array' (例如double)更改为您的应用程序需要的任何typed array。请注意,这个库只处理一维类型的数组;但这应该只是一个小障碍。

票数 16
EN

Stack Overflow用户

发布于 2017-05-21 03:25:12

我也能够重现你所经历的延迟,但也许没有你那么糟糕。我使用了以下代码

代码语言:javascript
复制
// main.js
const fork = require('child_process').fork

const child = fork('./getStats.js')

const dataAsNumbers = Array(100000).fill(0).map(() =>
  Array(100).fill(0).map(() => Math.round(Math.random() * 100)))

child.send({
  dataAsNumbers: dataAsNumbers,
})

代码语言:javascript
复制
// getStats.js
process.on('message', function (data) {
  console.log('data is ', data)
  process.exit(0)
})

节点main.js 2.72s用户0.45s系统103%cpu总计3.045

我正在生成由100个数字组成的100k元素来模拟您的数据,请确保您使用的是process上的message事件。但可能您的子项更复杂,可能是失败的原因,这也取决于您在查询中设置的超时。

如果你想得到更好的结果,你可以做的是将你的数据分成多个块,这些块将被发送给子进程,并重新构建以形成初始数组。

还有一种可能是使用第三方库或协议,即使这需要更多的工作。您可以查看一下messenger.js,或者甚至是类似于AMQP队列的东西,这些队列允许您使用池在两个进程之间进行通信,并且子进程已确认消息的保证。它有几个节点实现,比如amqp.node,但它仍然需要一些设置和配置工作。

票数 1
EN

Stack Overflow用户

发布于 2017-05-22 10:02:48

为什么要生成子流程?跨子进程发送数据在cpu和实时方面的成本可能比在同一进程内进行处理所节省的成本更高。

相反,我建议您考虑在与nodejs主进程相同的内存中运行的工作线程中进行统计计算,以获得超高效率的编码。

您可以使用NAN编写可以发布到工作线程的C++代码,然后让该工作线程在完成后将结果和事件发送回您的nodejs事件循环。

这样做的好处是您不需要额外的时间将数据发送到不同的进程,但缺点是您将为线程操作编写一些C++代码,但NAN扩展应该会为您处理大部分困难的任务。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44052913

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档