0

我正在为财务计算实施 REST 服务。所以每个请求都应该是一个 CPU 密集型任务,我认为创建线程的最佳位置是在以下函数中:

exports.execute = function(data, params, f, callback) {

    var queriesList = [];
    var resultList = [];

    for (var i = 0; i < data.lista.length; i++) 
    {
        var query = (function(cod) {

            return function(callbackFlow) {

                params.paramcodneg = cod;

                doCdaQuery(params, function(err, result)
                {
                    if (err) 
                    {
                        return callback({ERROR: err}, null);
                    }

                    f(data, result, function(ret)
                    {
                        resultList.push(ret);
                        callbackFlow();
                    });
                });
            }
        })(data.lista[i]);

        queriesList.push(query);
    }

    flow.parallel(queriesList, function() {
        callback(null, resultList);
    });
};

我不知道什么是最好的,在单独的线程中运行 flow.parallel 或在其自己的线程中运行 queriesList 的每个函数。什么是最好的?以及如何为此使用threads-a-gogo模块?

我已经尝试过,但无法为此编写正确的代码。

提前致谢。克莱森里奥斯。

4

1 回答 1

1

我承认我对 node.js 比较陌生,而且我还没有使用过线程 a gogo,但是我对多线程编程有一些经验,所以我会尝试回答这个问题。

为每个查询创建一个线程(我假设这些查询是 CPU 密集型计算,而不是对数据库的 IO 密集型调用)不是一个好主意。在昂贵的操作中创建和销毁线程,因此为每个需要计算的请求创建销毁一组线程将对性能造成巨大的拖累。当处理器在它们之间切换时,太多的线程会导致更多的开销。拥有比处理器内核更多的工作线程没有任何优势。

此外,如果每个查询不花费那么多处理时间,那么创建和销毁线程所花费的时间将比运行查询多。大部分时间将花在线程开销上。在这种情况下,您最好使用使用流或异步的单线程解决方案,它将处理分布在多个滴答声中,以允许 node.js 事件循环运行。

单线程解决方案是最容易理解和调试的,但如果查询阻止主线程完成其他工作,那么多线程解决方案是必要的。

您提出的多线程解决方案非常好。在单独的线程中运行所有查询可以防止主线程陷入困境。但是,在这种情况下使用 flow 或 async 没有任何意义。这些模块通过将处理分布在多个 node.js 滴答上来模拟多线程,并且并行运行的任务不会以任何特定的顺序执行。但是,这些任务仍然在单个线程中运行。由于您在自己的线程中处理查询,并且它们不再干扰 node.js 事件循环,因此只需在循环中一个接一个地运行它们。由于所有操作都发生在没有 node.js 事件循环的线程中,因此使用 flow 或 async in 只会引入更多开销而没有额外的好处。

一个更有效的解决方案是在后台挂出一个线程池并向其抛出任务。理想情况下,线程池与处理器内核具有相同数量的线程,并且会在应用程序启动时创建并在应用程序关闭时销毁,因此昂贵的线程创建和销毁只发生一次。我看到 Threads a Gogo 有一个你可以使用的线程池,但恐怕我对它还不够熟悉,无法为你提供使用它的所有细节。

我正在进入我不熟悉的领域,但我相信你可以通过将每个查询单独推送到全局线程池中来做到这一点,当所有回调都完成时,你就完成了。

Node.flow 模块在这里很方便,不是因为它会使处理更快,而是因为它可以帮助您管理所有查询任务及其回调。您将使用循环使用 flow.parallel(...) 将一堆并行任务推送到流堆栈上,其中每个任务将使用 threadpool.any.eval() 向全局线程池发送查询,然后调用 ready () 在线程池回调中告诉流程任务已完成。并行任务排队后,使用 flow.join() 运行所有任务。那应该在线程池上运行查询,线程池一次运行尽可能多的任务,使用所有内核并避免创建或销毁线程,并且所有查询都将被处理。

其他请求也将把它们的任务扔到线程池中,但是您不会注意到这一点,因为正在处理的请求只会获得请求提供给线程池的任务的回调。请注意,这一切都将在主线程上完成。线程池将完成所有非主线程处理。

你需要做一些线程 gogo 和 node.flow 文档阅读并找出一些细节,但这应该会给你一个良好的开端。使用单独的线程比使用主线程更复杂,使用线程池更复杂,因此您必须选择最适合您的线程。额外的复杂性可能值得也可能不值得。

于 2015-01-30T18:07:16.197 回答