Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/40.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Node.js NodeJS异步队列太快(减慢异步队列方法)_Node.js_Loops_Asynchronous_Web Crawler - Fatal编程技术网

Node.js NodeJS异步队列太快(减慢异步队列方法)

Node.js NodeJS异步队列太快(减慢异步队列方法),node.js,loops,asynchronous,web-crawler,Node.js,Loops,Asynchronous,Web Crawler,我有一个HTTPGET请求,我想解析响应并将其保存到我的数据库中 如果我独立地调用crawl(i),我会得到很好的结果。但是我必须从1到2000调用crawl()。 我得到了很好的结果,但有些反应似乎丢失了,有些反应是重复的。我不知道如何调用成千上万的异步函数。我正在使用队列函数,但到目前为止,我仍然缺少一些数据,并且仍然有一些重复数据。我做错了什么?谢谢你的帮助 我的节点功能: function getOptions(i) { return { host: 'mag

我有一个HTTPGET请求,我想解析响应并将其保存到我的数据库中

如果我独立地调用crawl(i),我会得到很好的结果。但是我必须从1到2000调用crawl()。 我得到了很好的结果,但有些反应似乎丢失了,有些反应是重复的。我不知道如何调用成千上万的异步函数。我正在使用队列函数,但到目前为止,我仍然缺少一些数据,并且仍然有一些重复数据。我做错了什么?谢谢你的帮助

我的节点功能:

 function getOptions(i) {
    return {
        host: 'magicseaweed.com',
        path: '/syndicate/rss/index.php?id='+i+'&unit=uk',
        method: 'GET'
    }
};

function crawl(i){
var req = http.request(getOptions(i), function(res) {
    res.on('data', function (body) {
        parseLocation(body);
    });
});
req.end();

}

function parseLocation(body){
    parser.parseString(body, function(err, result) {
        if(result && typeof result.rss != 'undefined') {
            var locationTitle = result.rss.channel[0].title;
            var locationString = result.rss.channel[0].item[0].link[0];
            var location = new Location({
                id: locationString.split('/')[2],
                name: locationTitle
            });
            location.save();
        }
    });
  }

N = 2 //# of simultaneous tasks
var q = async.queue(function (task, callback) {
        crawl(task.url);
        callback();
}, N);


q.drain = function() {
    console.log('Crawling done.');
}

for(var i = 0; i < 100; i++){
   q.push({url: 'http://magicseaweed.com/syndicate/rss/index.php?id='+i+'&unit=uk'});
}
函数getOptions(i){ 返回{ 主持人:“magicseaweed.com”, 路径:'/syndicate/rss/index.php?id='+i+'&unit=uk', 方法:“获取” } }; 函数爬网(一){ var req=http.request(getOptions(i)、函数(res){ res.on(‘数据’、函数(正文){ 位置(体); }); }); 请求结束(); } 函数解析位置(正文){ parser.parseString(主体、函数(错误、结果){ if(result&&typeof result.rss!=“未定义”){ var locationTitle=result.rss.channel[0].title; var locationString=result.rss.channel[0]。项[0]。链接[0]; var位置=新位置({ id:locationString.split('/')[2], 姓名:locationTitle }); location.save(); } }); } N=2/#个同时任务 var q=async.queue(函数(任务、回调){ 爬网(task.url); 回调(); },N); q、 drain=函数(){ console.log('爬行完成'); } 对于(变量i=0;i<100;i++){ q、 推送({url:'http://magicseaweed.com/syndicate/rss/index.php?id=“+i+”&unit=uk'}); } [编辑]经过大量测试,我正在爬网的服务似乎无法处理如此多的请求。因为当我按顺序处理每个请求时,我可以得到所有良好的响应


有没有办法降低异步队列方法的速度?

您应该看看这个伟大的模块,它简化了类似这样的异步任务。您可以使用队列,简单示例如下:

N = # of simultaneous tasks
var q = async.queue(function (task, callback) {
    somehttprequestfunction(task.url, function(){
    callback();
    } 
}, N);


q.drain = function() {
    console.log('all items have been processed');
}

for(var i = 0; i < 2000; i++){
   q.push({url:"http://somewebsite.com/"+i+"/feed/"});
}
N=#同时执行的任务
var q=async.queue(函数(任务、回调){
somehttprequestfunction(task.url,function()){
回调();
} 
},N);
q、 drain=函数(){
console.log('所有项目都已处理');
}
对于(变量i=0;i<2000;i++){
q、 推送({url:http://somewebsite.com/“+i+”/feed/”});
}
它将有一个正在进行的操作窗口,如果您只调用回调函数,任务室将可用于未来的任务。不同的是,您的代码现在立即打开2000个连接,显然失败率很高。将其限制在合理的值5,10,20(取决于站点和连接)将导致更高的成功率。如果请求失败,您始终可以重试,或将任务推送到另一个异步队列以进行另一次尝试。关键是在队列函数中调用callback(),以便在完成任务后,房间可用

var q = async.queue(function (task, callback) {
    crawl(task.url);
    callback();
}, N);
在启动上一个任务后,您将立即执行下一个任务,这样,队列就没有意义了。您应该像这样修改代码:

// first, modify your 'crawl' function to take a callback argument, and call this callback after the job is done.

// then
var q = async.queue(function (task, next/* name this argument as 'next' is more meaningful */) {
    crawl(task.url, function () {
        // after this one is done, start next one.
        next();
    });     
    // or, more simple way, crawl(task.url, next);
}, N);

如果您想要.Vanilla JS而不需要花哨的库,还有另一个选择

var incrementer = 0;
var resultsArray = [];

var myInterval = setInterval(function() {
    incrementer++
    if(incrementer == 100){
        clearInterval(myInterval)
        //when done parse results array
    }
    //make request here
    //push request result to array here

}, 500);

每半秒调用一次函数。在x个请求后强制同步和退出的简单方法。

我知道我回答这个问题有点晚,但是我编写了一个解决方案,在测试api端点时,使用节点4或节点5来降低请求数:

var fs = require('fs');
var supertest = require('supertest');
var request = supertest("http://sometesturl.com/api/test/v1/")
var Helper = require('./check.helper');
var basicAuth = Helper.basicAuth;
var options = Helper.options;

fs.readFile('test.txt', function(err, data){
  var parsedItems = JSON.parse(data);
  var urlparts = []
  // create a queue
  for (let year of range(1975, 2016)) {
    for (var make in parsedItems[year]){
      console.log(year, make, '/models/' + year + '/' + make)
      urlparts.push({urlpart:'/models/' + year + '/' + make, year: year, make: make})
    }
  }
  // start dequeue
  waitDequeue();

  // This function calls itself after the makeRequest promise completes
  function waitDequeue(){
    var item = urlparts.pop()
    if (item){
      makeRequest(item)
        .then(function(){
          // wait this time before next dequeue
          setTimeout(function() {
            waitDequeue();
          }, 3000);
        })
    } else {
      write(parsedItems)
    }
  }

  // make a request, mutate parsedItems then resolve
  function makeRequest(item){
    return new Promise((resolve, reject)=>{
      request
        .get(item.urlpart)
        .set(options.auth[0], options.auth[1])
        .set(options.type[0], options.type[1])
        .end(function(err, res) {
          if (err) return done1(err);
          console.log(res.body)
          res.body.forEach(function(model){
            parsedItems[item.year][item.make][model] = {}
          });
          resolve()
        })
      })
  }

  // write the results back to the file
  function write(parsedItems){
    fs.writeFile('test.txt', JSON.stringify(parsedItems, null, 4), function(err){
      console.log(err)
    })
  }

})

有点晚了,但我发现这是有效的! 使用async,您可以在任务处理程序内部使用以下命令来减慢队列速度,例如:

var q = async.priorityQueue(function(task, callback) {
// your code process here for each task
//when ready to complete the task delay it by calling
async.whilst( //wait 6 seconds
   function() {         
        return count < 10;      
   },
   function(callback) {
      count++;
      setTimeout(function() {
        callback(null, count);
      }, 1000);
   },
   function (err, n) {
    // n seconds have passed  
    callback(); //callback to q handler 
   }
 ); //whilst
} , 5);
var q=async.priorityQueue(函数(任务,回调){
//您在这里为每个任务编写代码流程
//准备完成任务时,通过调用
async.while(//等待6秒
函数(){
返回计数<10;
},
函数(回调){
计数++;
setTimeout(函数(){
回调(null,count);
}, 1000);
},
函数(err,n){
//n秒过去了
callback();//对q处理程序的回调
}
);//同时
} , 5);

我尝试了您的解决方案,但仍然有重复的问题和大量缺少的回答。我已经更新了我的问题和代码,请您进一步解释一下好吗?谢谢。由于您的请求很简单,您可以使用,我现在看不出您的代码有什么问题。他们是在等待限制每秒从队列中弹出多少项吗?您是miNoDE.js没有被处理的函数作为C++或VB的标准阻塞效应,所以一旦调用,它就在不等待响应的情况下为下一个调用提前。太长了,读不下去了,如果你的爬行函数只具有顺序操作(如数学),那么使用AcYNC的前提将允许在服务器中创建任务缓冲区,这样,你的代码不会受到大量连接和响应的延迟,TL;DR的影响。这一切都将完美地工作现在似乎很多请求都失败了…我如何确保请求不会失败?您是否尝试使用setTimeOut延迟
回调()
调用您的队列工作者函数?您可以通过这种方式减慢队列中任务的执行速度。我们过去使用这种方法,但它确实存在一个问题:与任何HTTP相关的服务一样,都有限制,同时您可以知道最大请求速率并调整间隔,如果服务器阻塞,则它之后的所有请求都将得到503(请求太多),否则您将不得不保持较低的限额以补偿此损失