【问题标题】:execute a function parallely, while completing execution of rest of the code并行执行一个函数,同时完成其余代码的执行
【发布时间】:2013-07-27 04:57:52
【问题描述】:

我在nodejs中有这样的代码sn-p:

每 2 秒调用一次 foo()。

function foo() 
{
    while (count < 10) 
    {
        doSometing()
        count ++;``
     }
}

doSomething()
{
   ...
}

限制是, foo() 没有回调。 如何使 while 循环执行和 foo() 完成而不等待 dosomething() 完成(调用 dosomething() 并继续),并且 dosomething() 并行执行?

【问题讨论】:

    标签: node.js


    【解决方案1】:

    我想,你想要的是:

    function foo() 
    {
        while (count < 10) 
        {
            process.nextTick(doSometing);
            count ++;
         }
    }
    

    process.nextTick 将安排在事件循环的下一个滴答时执行doSometing。因此,这段代码不会立即切换到doSometing,而是安排执行并首先完成foo

    您也可以试试setTimeout(doSometing,0)setImmediate(doSometing)。他们将允许在执行doSometing 之前发生I/O 调用。

    将参数传递给doSomething

    如果你想将一些参数传递给doSomething,那么最好确保它们被封装并且在doSomething被执行之前不会改变:

    setTimeout(doSometing.bind(null,foo,bar),0);
    

    在这种情况下,doSometing 将使用正确的参数调用,即使 foobar 将被更改或删除。但是,如果 foo 是一个对象并且您更改了它的一个属性,这将不起作用。

    有哪些替代品?

    如果您希望doSomething 并行执行(不仅仅是异步,而是实际上是并行执行),那么您可能对一些作业处理解决方案感兴趣。推荐你看kickq

    var kickq = require('kickq');
    
    kickq.process('some_job', function (jobItem, data, cb) {
      doSomething(data);
      cb();
    });
    
    // ...
    
    function foo() 
    {
        while (count < 10) 
        {
            kickq.create('some_job', data);
            count ++;
         }
    }
    

    kickq.process 将创建一个单独的进程来处理您的作业。所以,kickq.create 只会注册要处理的作业。

    kickq 使用redis 对作业进行排队,没有它就无法工作。

    使用 node.js 内置模块

    另一种选择是使用Child Process 构建您自己的作业处理器。生成的代码可能如下所示:

    var fork = require('child_process').fork,
        child = fork(__dirname + '/do-something.js');
    
    // ...
    
    function foo() 
    {
        while (count < 10) 
        {
            child.send(data);
            count ++;
         }
    }
    

    do-something.js 这是一个单独的.js 文件,带有doSomething 逻辑:

    process.on('message', doSomething);
    

    实际代码可能更复杂。

    您应该注意的事项

    Node.js 是单线程的,所以它一次只执行一个函数。它也不能使用超过一个 CPU。

    Node.js 是异步的,因此它能够通过在多个函数之间切换来一次处理多个函数。在处理具有大量 I/O 调用的函数时,它非常有效,因为它是较新的块。因此,当一个函数等待来自 DB 的响应时,会执行另一个函数。但node.js 不是阻塞 CPU 使用率高的任务的好选择。

    可以使用child_processcluster 等模块在node.js 中进行真正的并行计算。 child_process 允许您启动一个新的node.js 进程。它还创建了父进程和子进程之间的通信通道。集群允许您运行相同进程的集群。当您处理http 请求时,它真的很方便,因为cluster 可以在工作人员之间随机分配它们。因此,尽管node.js 通常是单线程的,但可以创建一个并行处理数据的工作人员集群。

    【讨论】:

    • @Lenoid 我知道 process.nextTick() 会起作用。但是 nextTick() 在任何 I/O 之前执行排队事件。见这里:stackoverflow.com/questions/16220710/…。这里 foo() 是一个 I/O 调用,我想 doSomething() 在后台执行,下一个 foo() 开始执行。但是 nextTick() 将使所有排队的 doSomething() 在开始下一个 foo() 之前执行。
    • 然后使用setTimeout。它不会阻止I/O 操作。
    • @Leonid 可能会有帮助
    • 除了使用child_process 在单独的进程中执行doSometing 之外,没有其他内置方式可以这样做。您可能还对一些工作处理工具感兴趣,例如kickq。如果您愿意,我可以为这两种解决方案添加示例。
    • @Leonid setTimeout,它似乎将函数调用放入某个队列并在时间间隔到期后一一执行。现在,如果函数正在修改一个变量,那么每个函数都会获得该变量的修改值(由先前的调用修改)。如果 doSomething 应该作为线程工作怎么办,这意味着每个调用都将具有原始变量,而不是前一个调用修改的变量。是的,就像你建议的那样 child_process 。如果您可以为您在之前的评论中讨论的其他方式提供一些示例,那将是 gud。谢谢。
    猜你喜欢
    • 1970-01-01
    • 2017-10-08
    • 2019-12-01
    • 2016-10-29
    • 1970-01-01
    • 1970-01-01
    • 2017-10-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多