【问题标题】:node.js - mutual variablenode.js - 互变量
【发布时间】:2016-03-26 18:25:34
【问题描述】:

我是 node.js 的新手,所以在发布我的 node.js 应用程序之前,我需要确保它能够正常工作。

假设我有一个数组变量,我在脚本开始时初始化它

myArray = [];

然后我从外部 API 中提取一些数据,将其存储在 myArray 中,并使用 setInterval() 方法每 30 分钟再次提取这些数据:

pullData();
setInterval(pullData, 30*60*1000);

pullData() 函数大约需要 2-3 秒才能完成。

客户端将能够使用此函数获取 myArray:

http.createServer(function(request, response){
var path = url.parse(request.url).pathname;
if(path=="/getdata"){

    var string = JSON.stringify(myArray);
    response.writeHead(200, {'Content-Type': 'text/plain'});
    response.end(string);              

}
}).listen(8001);

所以我要问的是,下一种情况会发生吗?: 客户端尝试从该 node.js 服务器获取数据,并且在同一时刻,pullData() 函数正在将数据写入 myArray,导致向客户端发送无效数据?

我阅读了一些文档,我意识到当 pullData() 运行时,createServer() 将在 pullData() 完成其工作之前不会响应客户端? 我真的不擅长理解并发编程,所以我需要您确认一下,或者您是否有更好的解决方案?

编辑:这是我的 pullData() 函数的代码:

 var now = new Date();

Date.prototype.addDays = function(days){

        var dat = new Date(this.valueOf());
        dat.setDate(dat.getDate() + days);
        return dat;
}


var endDateTime = now.addDays(noOfDays);
var formattedEnd = endDateTime.toISOString(); 

var url = "https://api.mindbodyonline.com/0_5/ClassService.asmx?wsdl";
    soap.createClient(url, function (err, client) {
        if (err) {
            throw err;
        }

        client.setEndpoint('https://api.mindbodyonline.com/0_5/ClassService.asmx');
        var params = {
            "Request": {
                "SourceCredentials": {
                    "SourceName": sourceName,
                    "Password": password,
                    "SiteIDs": {
                        "int": [siteIDs]
                    }
                },
                "EndDateTime" : formattedEnd

            }
        };


client.Class_x0020_Service.Class_x0020_ServiceSoap.GetClasses(params, function (errs, result) {
            if (errs) {
                console.log(errs);
            } else {

                    var classes = result.GetClassesResult.Classes.Class;
                    myArray = [];

                    for (var i = 0; i < classes.length; i++) {
                        var name = classes[i].ClassDescription.Name;
                        var staff = classes[i].Staff.Name;
                        var locationName = classes[i].Location.Name;
                        var start = classes[i].StartDateTime.toISOString();
                        var end = classes[i].EndDateTime.toISOString();
                        var klasa = new Klasa(name,staff,locationName,start,end);

                        myArray.push(klasa);
                    }

                    myArray.sort(function(a,b){
                        var c = new Date(a.start);
                        var d = new Date(b.start);
                        return c-d;
                    });

                    string = JSON.stringify(myArray);
     }
        })


    });

【问题讨论】:

  • 为什么不用数据库来存储数据呢?如果您需要性能,请将其缓存。此外,如果您开始使用多台机器进行扩展,每台机器最终会得到不同的myArray,并且客户端获得的响应将取决于接收请求的机器!这对于小型服务器来说可以正常工作,并且数据将被存储,直到您重新启动服务器!
  • 这样没问题,要存储的数据不多,每次启动服务器都会重新拉取数据,所以重启服务器时丢失数据是没有问题的。我不会将它与数据库复杂化。无论如何感谢您的回复:)

标签: javascript node.js concurrent-programming


【解决方案1】:

不,NodeJs 不是多线程的,所有东西都在单线程上运行,这意味着除了非阻塞调用(即 IO)之外,其他所有东西都会占用 CPU 直到它返回,并且 NodeJS 绝对不会中途返回向最终用户填充数组,只要您只执行一次 HTTP 调用来填充数组

更新: 正如@RyanWilcox 所指出的那样,任何异步(非阻塞系统调用)调用都可能暗示 NodeJS 解释器让您的函数执行中途离开并稍后返回。

【讨论】:

  • "只要你只做一个 HTTP 调用来填充你的数组。" 任何异步操作 i>.
  • @Boynux 请看我的 pullData() 函数,我刚刚在第一篇文章中添加了它,看看这是否可以正常工作?
  • 很难回答,如果我假设来自soap客户端的GetClasses方法不做任何异步调用,只是用数据调用你的回调,是的,这是安全的。
  • GetClasses 不是soap 客户端方法,它是API 的SOAP 端点。那么它应该是安全的吗?
  • 对,它是您的 SOAP 类的代理。我最好的猜测是肯定的,它是安全的。这是我对 SOAP 的理解。但是我不确定 JS SOAP 客户端的实现。这就是为什么它只是一个猜测:)
【解决方案2】:

一般来说:没有。

JavaScript 是单线程的。当一个函数正在运行时,没有其他函数可以运行。

例外情况是访问数组值的函数之间存在延迟。

例如

var index = i;
function getNext() {
    async.get(myArray[i], function () {
        i++;
        if (i < myArray.length) {
            getNext()
        }
    });
}

...在这种情况下,可以在调用异步函数之间更新数组。

您可以通过在启动第一个异步操作时创建数组的 deep copy 来缓解这种情况。

【讨论】:

  • 感谢您的广泛回答。我的 pullData 函数每 30 分钟只更新一次 myArray,所以这应该没问题;)
【解决方案3】:

Javascript 是单线程语言,因此您不必担心这种并发性。这意味着不会同时执行两部分代码。与许多其他编程语言不同,javascript 具有基于event loop 的不同并发模型。为了获得最佳性能,您应该使用由回调函数、承诺或事件处理的非阻塞操作。我想您的外部 API 提供了一些非常适合 node.js 的异步 i/o 函数。

【讨论】:

    【解决方案4】:

    如果您的 pullData 调用不会花费太长时间,另一种解决方案是缓存数据。

    仅在需要时获取数据(即当客户端访问 /getdata 时)。如果它被提取,您可以使用时间戳缓存数据。如果再次调用 /getdata,检查缓存数据是否超过 30 分钟,如果是,则再次获取。

    还将数组解析为json..

    var string = JSON.stringify(myArray);
    

    ..可能在 /getdata 调用之外完成,因此不必为每个访问 /getdata 的客户端完成。可能会稍微快一点。

    【讨论】:

    • 不能只在需要的时候取数据,因为API调用次数的限制,必须30分钟一次,取数据的新鲜度不是那么重要,30分钟是好的。并感谢有关将 stringify() 代码行移出 /getdata 调用的建议,它应该会加快响应速度。
    • 也许我的回答不够清楚。如果您使用正确的缓存,您不会超过每 30 分钟获取一次。如果缓存的数据超过 30 分钟,它只会再次获取。实际上,如果两个小时内只有一个访问者,那么您对 ​​api 的调用就只有 1 次,而不是 4 次(如果使用 30 分钟的间隔,则需要 4 次调用)。
    猜你喜欢
    • 1970-01-01
    • 2011-07-23
    • 2020-12-11
    • 2017-01-17
    • 1970-01-01
    • 1970-01-01
    • 2015-01-28
    相关资源
    最近更新 更多