数百个坐标之间的Nodejs距离计算阻塞了我的服务器

时间:2015-08-20 08:39:06

标签: javascript node.js asynchronous geolocation

我有一个包含数百个坐标(lat,lon)的列表。 对于每个客户端请求,我需要计算每对这些点之间的距离。 对于1000个坐标的列表 - 我需要500毫秒才能做到这一点,所以它阻塞了我的nodejs服务器。 我该怎样修理'通过使它异步?我不希望它阻止我的服务器,以便它可以继续处理其他请求..

是否建议打开另一个nodejs进程并使其成为距离计算服务'或类似的东西?

以下是测试代码示例:

var pts=[];
for (i=0;i<1000;i++){
    pts.push(randomLatLon());
}
var a;
var b;
var i,j;
var start = new Date();
for (i=0;i<pts.length;i++){
    for (j=0;j<pts.length;j++){
        if (i===j) {
            continue;
        }
        a = pts[i];
        b = pts[j];
        var dist = utils.getDistance(a.lat,a.lon,b.lat,b.lon);
    }
}
console.log('total time',new Date()-start,'ms'); // ~500 ms

这里是utils.getDistance函数:

E.getDistance = function(lat1,lon1,lat2,lon2) {
  var R = 6371*1000; // Radius of the earth in m
  var dLat = deg2rad(lat2-lat1);  // deg2rad below
  var dLon = deg2rad(lon2-lon1); 
  var a = 
    Math.sin(dLat/2) * Math.sin(dLat/2) +
    Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * 
    Math.sin(dLon/2) * Math.sin(dLon/2);
  var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
  var d = R * c; // Distance in m
  return d;
}

1 个答案:

答案 0 :(得分:1)

这取决于你需要对结果做些什么。您需要一系列距离作为输出吗?

一种方法是使用诸如Q之类的promise来将每个计算组合成一个单独的操作,然后使用Q.all等待所有计算的完成,但对1000x1000执行此操作可能不是一个好主意虽然你必须在内存中保留50万个承诺的数组。根据您需要对输出执行的操作以及原始点阵列的大小,按顺序调用每个计算可能会也可能不会更好。一种方法是使用递归:

function calculateDistances(pts) {
    var start = new Date();
    calculateNextDistance(pts, 0, 1).then(function() {
        console.log('total time',new Date()-start,'ms');
    });

    function calculateNextDistance(pts, i, j) {
        return Q().then(function () {
            var a = pts[i];
            var b = pts[j];
            var dist = utils.getDistance(a.lat, a.lon, b.lat, b.lon);

            j++;

            if (j == pts.length) {
                i++;
                j = i + 1;
            }

            if (j < pts.length) {
                return calculateNextDistance(pts, i, j);
            }
        });
    }
}

这对我来说似乎很有效,但请注意,由于所有上下文切换,现在完成计算当然需要比500毫秒更长的时间。一个折衷方案可能是在每次迭代中进行一些计算。

(顺便说一句,你可以通过不计算x-&gt; y和y-&gt; x来消除相当多的计算,这意味着循环可以for (j=i+1;j<pts.length;j++),我也在上面的代码中使用了

不管是否最好生成一个我不知道的子进程,它可能值得尝试。