Node.js使用threads-a-gogo进行多线程处理

时间:2014-10-01 20:07:19

标签: node.js threads-a-gogo

我正在实施一项用于财务计算的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);
    });
};

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

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

提前致谢。 Kleyson Rios。

1 个答案:

答案 0 :(得分:1)

我承认我对node.js相对较新,我还没有使用线程gogo,但我有一些多线程编程的经验,所以我&#39我会回答这个问题。

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

此外,如果每个查询都没有花费那么多处理时间,那么创建和销毁线程所花费的时间比运行查询要多。大部分时间都花在线程开销上。在这种情况下,使用flow或async的单线程解决方案会更好,它会将处理分配到多个tick,以允许node.js事件循环运行。

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

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

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

我已经进入了我不熟悉的领域,但我相信你可以通过将每个查询单独推送到全局线程池来完成它,当所有回调都完成后,你就可以了。我会完成的。

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

其他请求也会将他们的任务抛给线程池,但你不会注意到,因为正在处理的请求只会获得请求给线程池的任务的回调。请注意,这将全部在主线程上完成。线程池将执行所有非主线程处理。

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