【问题标题】:node.js, can external request alter variables in a running functionnode.js,可以外部请求更改正在运行的函数中的变量
【发布时间】:2012-11-05 11:32:34
【问题描述】:

我已经设置了一个节点服务器来保存日志信息。预计会有非常大量的请求进入。我正在使用 mongo 数据存储,但它的性能太不可靠了。读取事物报告方面的数据通常需要异常长的时间。所以我改用经典的mysql。如果您准备批量插入而不是单例插入,那么显然有显着的写入吞吐量优势。于是我找到了这个人:

https://gist.github.com/3078520

我喜欢它的简单。它只有几行,非常强大。它有两个主要功能add() 将向队列添加一条记录,然后在队列达到一定大小时调用flush()。然后它有flush() 它将队列加入一个长字符串并创建一个长的批量插入语句,然后将其发送到 mysql 驱动程序(我从提供的链接简化了函数:

this.flush = function () {
/*1*/    var sql = queryTemplate.replace('{values}', '\n('+ queue.join('),\n(') +')');
/*2*/    handle.query(sql, callback);
/*3*/    queue = [];
}

这本质上是一个类函数,它是请求处理程序拥有的单个类实例的一部分。所以我的问题是,这安全吗? queue 是一个类变量。当flush() 被调用时,它会处理队列。我能看到的唯一问题是如果 flush() 被调用,第 1 行被执行以创建 sql 语句(只是一个字符串),然后另一个 add() 被调用,它向 queue 添加了一些东西, 然后第一个进程调用query() 函数,然后清空队列。在这种情况下,第二个进程添加的记录将丢失,因为第一个进程在创建 sql 语句时不会知道它,并且在清除 queue 时会将其清除。这可能吗?

这个问题的更一般化的形式如下。一旦一个函数开始执行,其他任何外部因素都会影响其范围之外的变量吗?这是一个非常简单的示例,假设不同的请求调用这两个函数,是否可能在此示例中执行 console.log:

var global_number;
function a(){
  global_number=2;
}
function b(){
  global_number=1;
  if(global_number==2){
    console.log("a() influenced global_number in the middle of b()'s execution")
  }
}

这主要是一个是/否的问题,但我正在寻找更多。一个简短的解释或指向我可以了解更多信息的页面的链接会很棒!谢谢!

【问题讨论】:

    标签: javascript mysql node.js asynchronous


    【解决方案1】:

    是的,如果函数的执行是异步的,那么您可能会遇到全局变量拥有的数据的问题。这是测试场景;

    var globalVariable = 10;
    
    function a ()
    {
        var timer = setInterval(function() {
            globalVariable--;
            console.log(globalVariable)
        }, 1000);
    }
    
    function b ()
    {
        setTimeout(function() {
            globalVariable = 20;
        }, 3000);
    }
    
    a();
    b();
    

    这将输出:

    9
    8
    7
    19
    18
    17
    16
    

    如果你要求非异步的函数执行中断,没办法!请参阅示例。

    var globalVariable = 1000000000;
    function a () {
        for(var i=0; i < 1000000000; i++)
        {
            if(globalVariable == 20000) console.log('From a() : ' + globalVariable);
            globalVariable--;
            if(globalVariable == 0) break;
        }
    }
    
    function b () {
        setTimeout(function() {
            console.log('From b() : ' + globalVariable);
            globalVariable = 20000;
            console.log('From b() : ' + globalVariable);
        }, 1);
    }
    
    b();
    a();
    

    这将始终输出:

    From a() : 20000
    From b() : 0
    From b() : 20000
    

    所以,你的问题答案是否定的,你不能中断同步函数的执行。

    但是;在您的代码 sn-p 示例中,清空 queue 似乎没问题,因为您已经在第 1 行使用 queue.join 消耗了 queue 中的数据。另一方面,这种方法会受到回滚操作的影响。例如,当 sql 返回错误时,您可能无法重新填充 queue

    【讨论】:

    • 关于错误问题的好点,我不关心它,但记住这一点很好。除此之外,该功能是否以我描述的方式避免数据丢失?你上面的回答不是很清楚。
    • 第一句话是关于你的实际问题。不,这不安全,你的 async 函数可以修改全局数据,而所有其他使用相同全局变量的进程都会受到操作数据的影响。
    • 更新了答案,看输出,你会很容易上手的。
    • 这更清楚,但我的问题是可以在单个函数执行的中途更改全局变量。与您的示例相关,对 a() 和 b() 有各种调用,每个调用都是异步的(它们必须是,你等一下),但是当它们同时执行时,在 3 秒标记处存在争用时间。一个只是(随机)先走,执行到完成,然后另一个走?或者,换句话说,在本例中,一旦a() 启动,b() 是否有可能在 a() 完成执行之前运行
    • 我现在明白了。那么答案是否定的。您不能中断函数的执行。查看更新的答案。
    【解决方案2】:

    如果一个函数是同步的,那么在函数开始执行和完成之间,没有任何东西可以影响该函数引用的变量。

    但是,如果函数调用异步函数(例如 MySQL 查询),则函数本身是异步的,并且其他代码可以在函数运行时间和运行时间之间修改函数的父/全局范围内的变量异步函数的回调运行。

    【讨论】:

    • 我知道 query() 调用是异步的,并且会在稍后的时间点返回,但是当它被调用时,它知道 sql 语句。但是函数的其余部分是同步的吗?是否有可能以我描述的方式丢失上述函数中的记录?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-12
    • 2017-03-08
    • 1970-01-01
    • 2018-07-26
    • 1970-01-01
    相关资源
    最近更新 更多