欲看此文,必先可先看:

golang实现并发爬虫一(单任务版本爬虫功能)

gollang实现并发爬虫二(简单调度器)

上文中的用简单的调度器实现了并发爬虫。

并且,也提到了这种并发爬虫的实现可以提高爬取效率。

当workerCount为1和workerCount为10时其爬取效率是有明显不同的。

然而,文末其实也提到了这个简单调度器实现的爬虫有个不可控或者说是控制力太小了的问题。

究其原因就是因为我们实现的方法是来一个request就给创建一个groutine。

为了让这个程序变得更为可控。得想想怎么可以优化下了。

现在,非常明显,优化点就是我不想要来一个request就创建一个这个实现过程。

那么,我们可以想到队列。

把request放到request队列里。

那么,request队列里一定是会有一个request的头的,我们就可以把这个request的头元素给到worker去做实现。

也就是这样:

but,这样是没有对worker进行一个控制的。

我们希望request可以选择我们想要的一个worker。

那么,我们也可以让scheduler维护一个worker的队列。

这里用了三个并行的模块:

1.engine 引擎模块。

2.scheduler 调度器模块。

3.worker 工作模块。

这三者通信都是通过channel来通信的。

上图中可知道调度器模块实际上是维护了2个channel,一个是request的channel,一个是worker的channel。

//队列调度器
//这个scheduler与engine和worker之间的通信都是通过channel来连接的。
//故尔它的肚子里应该有request相关的channel和worker相关的channel.
//另外注意这里worker的channel的类型是chan Request。
type QueuedScheduler struct {
requestChan chan con_engine.Request
workerChan chan chan con_engine.Request
}

那么,我们就只需要在这个scheduler调度器的两个channel里,各取一个元素,即取request和worker(chan con_engine.Request),把request发给worker就可以了。

一直不断的去取和发送,这就是这个队列调度器要做的事情了。

那个弯曲的箭头也就是指的这个事情了。在request的队列里找到合适的request发给worker队列里合适的worker就好。

这就是一个整体的思想了。

稍微说下关于维护如何两个队列的代码。

重点在于怎么才能做到各读取一个元素。

channel的读取是会阻塞的。

如果我先读取request,如果读取不到,那么在等待的时候就没有办法取到worker了。

解决方案就是用select,因为select会保证一点,select里的每一个case都会被执行到且会很快速的执行。

func (s *QueuedScheduler) Run() {
s.requestChan = make(chan con_engine.Request) //指针接收者才能改变里面的内容。
s.workerChan = make(chan chan con_engine.Request)
go func() {
var requestQ []con_engine.Request
var workerQ []chan con_engine.Request
for {
var activeRequest con_engine.Request
var activeWorker chan con_engine.Request
if len(requestQ) > && len(workerQ) > {
activeRequest = requestQ[]
activeWorker = workerQ[]
}
//收到一个request就让request排队,收到一个worker就让worker排队。所有的channel操作都放到select里。
select {
case r := <-s.requestChan:
requestQ = append(requestQ, r)
case w := <-s.workerChan:
workerQ = append(workerQ, w)
case activeWorker <- activeRequest:
requestQ = requestQ[:]
workerQ = workerQ[:]
}
}
}()
}

select就是在做三件事情:

1.从requestChan里收一个request,将这个request存在变量requestQ里。

2.从workerChan里收一个worker,将这个worker存在变量workerQ里。

3.把第一个requestQ里的第一个元素发给第一个workerQ里的第一个元素。  

其他代码就感兴趣的同学自己看吧。

作者就先说到这里。

总体调度的思想上面的图中。

具体的实现在源码里。

欢迎大家留言指教。

源码:

https://github.com/anmutu/du_crawler/tree/master/04crawler

疫情期间的佛系小程序:

https://www.zmfei4.com/ (谐音:怎么肥四?)

店家已经不愿意经营,看看就好。

golang实现并发爬虫三(用队列调度器实现)的更多相关文章

  1. golang实现并发爬虫二(简单调度器)

    上篇文章当中实现了单任务版爬虫. 那么这篇文章就大概说下,如何在上一个版本中进行升级改造,使之成为一个多任务版本的爬虫.加快我们爬取的速度. 话不多说,先看图: 其实呢,实现方法就是加了一个sched ...

  2. golang实现并发爬虫一(单任务版本爬虫功能)

    目的是写一个golang并发爬虫版本的演化过程. 那么在演化之前,当然是先跑通一下单任务版本的架构. 正如人走路之前是一定要学会爬走一般. 首先看一下单任务版本的爬虫架构,如下: 这是单任务版本爬虫的 ...

  3. golang版并发爬虫

    准备爬取内涵段子的几则笑话,先查看网址:http://www.budejie.com/text/ 简单分析后发现每页的url呈加1趋势 第一页: http://www.budejie.com/text ...

  4. Golang调度器GMP原理与调度全分析(转 侵 删)

    该文章主要详细具体的介绍Goroutine调度器过程及原理,包括如下几个章节. 第一章 Golang调度器的由来 第二章 Goroutine调度器的GMP模型及设计思想 第三章 Goroutine调度 ...

  5. Golang/Go goroutine调度器原理/实现【原】

    Go语言在2016年再次拿下TIBOE年度编程语言称号,这充分证明了Go语言这几年在全世界范围内的受欢迎程度.如果要对世界范围内的gopher发起一次“你究竟喜欢Go的哪一点”的调查,我相信很多Gop ...

  6. 第1节 yarn:14、yarn集群当中的三种调度器

    yarn当中的调度器介绍: 第一种调度器:FIFO Scheduler  (队列调度器) 把应用按提交的顺序排成一个队列,这是一个先进先出队列,在进行资源分配的时候,先给队列中最头上的应用进行分配资源 ...

  7. scrapy 基础组件专题(七):scrapy 调度器、调度器中间件、自定义调度器

    一.调度器 配置 SCHEDULER = 'scrapy.core.scheduler.Scheduler' #表示scrapy包下core文件夹scheduler文件Scheduler类# 可以通过 ...

  8. 大数据之Yarn——Capacity调度器概念以及配置

    试想一下,你现在所在的公司有一个hadoop的集群.但是A项目组经常做一些定时的BI报表,B项目组则经常使用一些软件做一些临时需求.那么他们肯定会遇到同时提交任务的场景,这个时候到底如何分配资源满足这 ...

  9. MapReduce多用户任务调度器——容量调度器(Capacity Scheduler)原理和源码研究

    前言:为了研究需要,将Capacity Scheduler和Fair Scheduler的原理和代码进行学习,用两篇文章作为记录.如有理解错误之处,欢迎批评指正. 容量调度器(Capacity Sch ...

随机推荐

  1. HDU-1051 一个DP问题

    Problem Description There is a pile of n wooden sticks. The length and weight of each stick are know ...

  2. 终极指南:构建用于检测汽车损坏的Mask R-CNN模型(附Python演练)

    介绍 计算机视觉领域的应用继续令人惊叹着.从检测视频中的目标到计算人群中的人数,计算机视觉似乎没有无法克服的挑战. 这篇文章的目的是建立一个自定义Mask R-CNN模型,可以检测汽车上的损坏区域(参 ...

  3. 【Pytest05】全网最全最新的Pytest框架之用例分组执行

    一.Fixture用例分组运行常用于冒烟测试,分模块运行等 pytest.ini配置文件中增加分组参数markers来实现用例分组,如: markers = g1:组一 smoke:冒烟测试 pyte ...

  4. ML-Agents(四)GridWorld

    目录 ML-Agents(四)GridWorld Visual Observations Masking Discrete Actions 环境与训练参数 场景基本结构 代码分析 环境初始化代码 Ag ...

  5. Python——交互式图形编程

    一. 1.图形显示 图素法 像素法 图素法---矢量图:以图形对象为基本元素组成的图形,如矩形. 圆形 像素法---标量图:以像素点为基本单位形成图形 2.图形用户界面:Graphical User ...

  6. Windows 7 NVMe补丁(包括官网下载链接)

    随着NVMe固态硬盘的普遍,很多想使用Windows 7,又想使用NVMe固态硬盘的,不得不打两个NVMe补丁 这两个补丁主要是:KB2990941和KB3087873 32位 百度网盘 64位 百度 ...

  7. PTA数据结构与算法题目集(中文) 7-31

    PTA数据结构与算法题目集(中文)  7-31 7-31 笛卡尔树 (25 分)   笛卡尔树是一种特殊的二叉树,其结点包含两个关键字K1和K2.首先笛卡尔树是关于K1的二叉搜索树,即结点左子树的所有 ...

  8. andlua,andlua发送http请求,并解析json数据

    andlua发送http请求,并解析json实例 import'cjson'import 'http'--导入cjson库url = 'https://www.baidu,com'--设置urlHtt ...

  9. composer换源,composer切换国内源

    首先要分清楚是局部换源还是全局换源 1.局部换源(仅对当前项目有效) 在当前项目下的composer.json中添加 { "repositories": [ { "typ ...

  10. 初始WebApi(1)

    如果你要问我WebApi是干嘛,我只能说它是的给数据.哈哈哈哈哈,这几天也才刚刚了解了解关于WebApi的知识,今天就来谈谈吧. 1.创建WebApi项目 第一步:选择ASP.NET Web应用程序 ...