1.用 eventproxy 实现控制并发:

var EventProxy = require('eventproxy');

const most = 5;//并发数5
var urllist = [....];//待抓取url列表,100个 function foo(start){
var ep = new EventProxy();
ep.after('ok',most,function(){
foo(start+most);//一个批次任务完成,递归进行下一批任务
});
var q=0;
for(var i=start;i<urllist.length;i++){
if(q>=most){
break;//最多添加most个任务
}
http.get(urllist[i],function(res){
//....
res.on('end',function(){
ep.emit('ok');//一个任务完成,触发一次ok事件
});
});
q++;
}
}
foo(0);

2.使用 async.mapLimit 控制并发

var async = require('async');

//模拟一组连接地址
var urls = [];
for(var i = 0; i < 30; i++) {
urls.push('http://datasource_' + i);
}
console.log(urls); // 并发连接数的计数器
var concurrencyCount = 0; // 并发抓取数据的过程
var fetchUrl = function (url, callback) {
// delay 的值在 2000 以内,是个随机的整数
var delay = parseInt((Math.random() * 10000000) % 2000, 10);
concurrencyCount++;
console.log('现在的并发数是', concurrencyCount, ',正在抓取的是', url, ',耗时' + delay + '毫秒');
setTimeout(function () {
concurrencyCount--;
//抓取成功,调用回调函数
callback(null, url + ' html content');
}, delay);
}; //使用 async.mapLimit 来 5 个并发抓取,并获取结果
async.mapLimit(urls, 5, function (url, callback) {
fetchUrl(url, callback);
}, function (err, result) {
//所有连接抓取成功,返回回调结果列表
console.log('final:');
console.log(result);
});

3.async.queue 非常合适用来控制并发

/**
* Created by admin on 16/3/20.
*/
"use strict"
var http = require('http');
var cheerio = require('cheerio');
var URL = require('url');
var path = require('path');
var fs = require('fs');
var async = require('async'); var baseUrl = "http://cnodejs.org/";
var targetUrl = "http://cnodejs.org/";
var stime = new Date(); function sGet(url,callback){
var chunks = [];
http.get(url,(res)=>{
if (res.statusCode != '200') {
callback({message:"抓取失败,状态码:"+res.statusCode,url:url});
return;
}
res.on('data',(chunk)=>{
chunks.push(chunk);
});
res.on('end',()=>{
callback(null,Buffer.concat(chunks).toString());
});
}).on('error',(e)=>{
callback({message:"抓取失败",url:url,err:e});
});
} sGet(targetUrl,(err,data)=>{
if (err) {
console.log(err);
return false;
}
var $ = cheerio.load(data);
var anchors = $("#topic_list a.topic_title");
console.log('共'+anchors.length+'个任务'); const most=5;//并发数
//创建队列并指定并发数
var q=async.queue(function(url,callback){
var filename = path.basename(url)+'.txt';
sGet(url, (err, data)=> {
if (err) {
callback(err);
return false;
}
fs.writeFile('./html/' + filename, data, function (err) {
if (err) {
throw err;
}
callback(null,filename);
});
});
},most); q.drain = function() {
console.log('任务全部完成,共耗时:'+(new Date()-stime)+'ms');
} anchors.each(function(){
var url = URL.resolve(baseUrl,$(this).attr('href'));
q.push(url,function(err,filename){
if (err) {
console.log(err);
return;
}
console.log("finished:"+filename);
});
});
});

nodejs 并发控制的更多相关文章

  1. Nodejs爬虫进阶=>异步并发控制

    之前写了个现在看来很不完美的小爬虫,很多地方没有处理好,比如说在知乎点开一个问题的时候,它的所有回答并不是全部加载好了的,当你拉到回答的尾部时,点击加载更多,回答才会再加载一部分,所以说如果直接发送一 ...

  2. Nodejs爬虫进阶教程之异步并发控制

    Nodejs爬虫进阶教程之异步并发控制 之前写了个现在看来很不完美的小爬虫,很多地方没有处理好,比如说在知乎点开一个问题的时候,它的所有回答并不是全部加载好了的,当你拉到回答的尾部时,点击加载更多,回 ...

  3. 架构选型之Nodejs与Java

    前言: 身边越来越多的同事谈论Nodejs,谈其异步IO.事件回调.前后台统一一门语言,创业的朋友的第一个创业项目也选择了Nodejs,期望能够使用一种语言节省成本快速完成需求开发.与其他项目组的同事 ...

  4. java程序员的NodeJS初识篇

    摘要 作为一个一直用java来写后端的程序员用NodeJS来写后台,实在不是很爽.这里记下这两个月的NodeJS学习所遇之坑,与java转NodeJS的同仁共勉.学习时间不长,若有理解错误,望指正. ...

  5. nodejs 使用superagent+cheerio+eventproxy爬取豆瓣帖子

    //cnpm install superagent cheerio eventproxy fs pathvar superagent = require('superagent'); var chee ...

  6. nodejs爬虫案例笔记

    用nodeJs制作一个简单的网页爬虫 主要分为三个步骤,向目标请求数据,处理数据,打印数据.需要用到的模块有http,cheerio. 1.准备步骤,引入要使用的模块 2.向目标请求数据 http.g ...

  7. nodejs常用模块

    推荐的入门教程: <七天学会NodeJS>  https://github.com/nqdeng/7-days-nodejs <Node.js 包教不包会> https://g ...

  8. nodeJs + js 大文件分片上传

    简单的文件上传 一.准备文件上传的条件: 1.安装nodejs环境 2.安装vue环境 3.验证环境是否安装成功 二.实现上传步骤 1.前端部分使用 vue-cli 脚手架,搭建一个 demo 版本, ...

  9. NodeJs之OS

    OS Node.js提供了一些基本的底层操作系统的模块OS. API var os = require('os'); console.log('[arch] 操作系统CPU架构'+os.arch()) ...

随机推荐

  1. JavaScript中两种类型的全局对象/函数【转】

    Snandy Stop, thinking is the essence of progress. JavaScript中两种类型的全局对象/函数 这里所说的JavaScript指浏览器环境中的包括宿 ...

  2. 使用shell脚本build并创建ipa文件(转)

    前言 由于项目引入了敏捷开发,需要每天build出一个ipa供QA测试.此前是使用Xcode先achive出一个文件,再在 organizer->achives里发布ipa,一直感觉也没啥不方便 ...

  3. mongoexport遭遇Authentication failed

    今天使用mongoexport工具导出数据,遇到权限不足报错:[host]$mongoexport  -h 10.31.11.190:23820 -udbmgr -pMgr2mgdb -d rcmp ...

  4. Code First ef SQL Server 版本不支持数据类型“datetime2”

    When calling DbContext.SaveChanges, I get a DbUpdateException:An unhandled exception of type 'System ...

  5. Windows store app[Part 2]:全新的File System与Uri不匹配的问题

    在Win 8 App的安全沙箱内,除了使用文件选取器FileOpenPicker外,没有其他办法调用某个盘符的数据. 全新的Storage命名空间,借鉴了IOS与Android的设计. 下面引用一个图 ...

  6. C语言编程学习:写的秒速计算四则混合运算项目

    C语言是面向过程的,而C++是面向对象的 C和C++的区别: C是一个结构化语言,它的重点在于算法和数据结构.C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到输出(或实现 ...

  7. 【Selenium专题】 FAQ_对象识别_Compound class names are not supported

    测试代码 public void login(){ WebDriver driver = new ChromeDriver(); driver.get("http://IP:Port/cli ...

  8. 二十五、MongoDB 索引 和 explain 的使用

    一.索引基础 索引是对数据库表中一列或多列的值进行排序的一种结构,可以让我们查询数据库变得更快.MongoDB 的索引几乎与传统的关系型数据库一模一样,这其中也包括一些基本的查询优化技巧.创建索引的命 ...

  9. leetcode 33 Search in Rotated Sorted Array JAVA

    题目: 假设按照升序排序的数组在预先未知的某个点上进行了旋转. ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] ). 搜索一个给定的目标值,如果数组中存在这个 ...

  10. django 保存订单乐观锁的使用

    后端在生成订单表的时候,牵扯到如下的知识点: 1 事物 2 高并发 3 时间函数的使用 一,事务: from django.db import transaction save_id = transa ...