前言

在上一篇文章《Golang实现简单爬虫框架(3)——简单并发版》中我们实现了一个最简单并发爬虫,调度器为每一个Request创建一个goroutine,每个goroutineWorker队列中分发任务,发完就结束。所有的Worker都在抢一个channel中的任务。但是这样做还是有些许不足之处,比如控制力弱:所有的Worker在抢同一个channel中的任务,我们没有办法控制给哪一个worker任务。

其实我们可以自己做一个任务分发的机制,我们来决定分发给哪一个Worker

注意:本次并发是在上一篇文章简单并发实现的基础上修改,所以没有贴出全部代码,只是贴出部分修改部分,要查看完整项目代码,可以查看上篇文章,或者从github下载项目源代码查看

1、项目架构

在上一篇文章实现简单并发的基础上,我们修改下Scheduler的任务分发机制

  • Scheduler接收到一个Request后,不能直接发给Worker,也不能为每个Request创建一个goroutine,所以这里使用一个Request队列
  • 同时我们想对Worker实现一个更多的控制,可以决定把任务分发给哪一个Worker,所以这里我们还需要一个Worker队列
  • 当有了RequestWorker,我们就可以把选择的Request发送给选择的Worker

2、队列实现任务调度器

在scheduler目录下创建queued.go文件

package schedulerimport "crawler/engine"// 使用队列来调度任务type QueuedScheduler struct {requestChan chan engine.Request     // Request channel// Worker channel, 其中每一个Worker是一个 chan engine.Request 类型workerChan  chan chan engine.Request
}// 提交请求任务到 requestChannel
func (s *QueuedScheduler) Submit(request engine.Request) {s.requestChan <- request
}func (s *QueuedScheduler) ConfigMasterWorkerChan(chan engine.Request) {panic("implement me")
}// 告诉外界有一个 worker 可以接收 request
func (s *QueuedScheduler) WorkerReady(w chan engine.Request) {s.workerChan <- w
}func (s *QueuedScheduler) Run() {// 生成channels.workerChan = make(chan chan engine.Request)s.requestChan = make(chan engine.Request)go func() {// 创建请求队列和工作队列var requestQ []engine.Requestvar workerQ []chan engine.Requestfor {var activeWorker chan engine.Requestvar activeRequest engine.Request// 当requestQ和workerQ同时有数据时if len(requestQ) > 0 && len(workerQ) > 0 {activeWorker = workerQ[0]activeRequest = requestQ[0]}select {case r := <-s.requestChan: // 当 requestChan 收到数据requestQ = append(requestQ, r)case w := <-s.workerChan: // 当 workerChan 收到数据workerQ = append(workerQ, w)case activeWorker <- activeRequest: // 当请求队列和认读队列都不为空时,给任务队列分配任务requestQ = requestQ[1:]workerQ = workerQ[1:]}}}()
}复制代码

3、爬虫引擎

修改后的concurrent.go文件如下

package engineimport ("log"
)// 并发引擎
type ConcurrendEngine struct {Scheduler   SchedulerWorkerCount int
}// 任务调度器
type Scheduler interface {Submit(request Request) // 提交任务ConfigMasterWorkerChan(chan Request)WorkerReady(w chan Request)Run()
}func (e *ConcurrendEngine) Run(seeds ...Request) {out := make(chan ParseResult)e.Scheduler.Run()// 创建 goruntinefor i := 0; i < e.WorkerCount; i++ {createWorker(out, e.Scheduler)}// engine把请求任务提交给 Schedulerfor _, request := range seeds {e.Scheduler.Submit(request)}itemCount := 0for {// 接受 Worker 的解析结果result := <-outfor _, item := range result.Items {log.Printf("Got item: #%d: %v\n", itemCount, item)itemCount++}// 然后把 Worker 解析出的 Request 送给 Schedulerfor _, request := range result.Requests {e.Scheduler.Submit(request)}}
}func createWorker(out chan ParseResult, s Scheduler) {// 为每一个Worker创建一个channelin := make(chan Request)go func() {for {s.WorkerReady(in) // 告诉调度器任务空闲request := <-inresult, err := worker(request)if err != nil {continue}out <- result}}()
}
复制代码

4、main函数

package mainimport ("crawler/engine""crawler/scheduler""crawler/zhenai/parser"
)func main() {e := engine.ConcurrendEngine{Scheduler:   &scheduler.QueuedScheduler{},// 这里调用并发调度器WorkerCount: 50,}e.Run(engine.Request{Url:       "http://www.zhenai.com/zhenghun",ParseFunc: parser.ParseCityList,})
}
复制代码

运行结果如下:

5、总结

在这篇文章中我们使用队列实现对并发任务的调度,从而实现了对Worker的控制。我们现在并发有两种实现方式,但是他们的调度方法是不同的,为了代码的统一,所以在下一篇文章中的内容有:

  • 对项目做一个同构
  • 添加数据的存储模块。

如果想获取Google工程师深度讲解go语言视频资源的,可以在评论区留下邮箱。

项目的源代码已经托管到Github上,对于各个版本都有记录,欢迎大家查看,记得给个star,在此先谢谢大家

如果觉得博客不错,劳烦大人给个赞,

Golang实现简单爬虫框架(4)——队列实现并发任务调度相关推荐

  1. Golang实现简单爬虫框架(5)——项目重构与数据存储

    前言 在上一篇文章<Golang实现简单爬虫框架(4)--队列实现并发任务调度>中,我们使用用队列实现了任务调度,接下来首先对两种并发方式做一个同构,使代码统一.然后添加数据存储模块. 注 ...

  2. python爬虫网站简单_Python爬虫之简单爬虫框架实现

    简单爬虫框架实现 目录 框架流程 调度器 url管理器 网页下载器 网页解析器 数据处理器 具体演示效果 框架流程 调度器 #导入模块 import Url_Manager import parser ...

  3. golang爬虫框架colly简单介绍

    colly一款快速优雅的golang爬虫框架,简单易用,功能完备. colly 官网地址:http://go-colly.org/ colly github地址:github.com/gocolly/ ...

  4. 非零基础自学Golang 第17章 HTTP编程(上) 17.3 爬虫框架gocolly 17.3.1 gocolly简介

    非零基础自学Golang 文章目录 非零基础自学Golang 第17章 HTTP编程(上) 17.3 爬虫框架gocolly 17.3.1 gocolly简介 第17章 HTTP编程(上) 17.3 ...

  5. autoload.php beanbun_Beanbun: 简单开放的 PHP 爬虫框架

    Beanbun Beanbun 是用 PHP 编写的多进程网络爬虫框架,具有良好的开放性.高可扩展性. 项目地址:github.com/kiddyuchin.- 文档地址:beanbun.org 由来 ...

  6. nodejs和python爬虫 哪个好_简单好用的nodejs 爬虫框架分享

    这个就是一篇介绍爬虫框架的文章,开头就不说什么剧情了.什么最近一个项目了,什么分享新知了,剧情是挺好,但介绍的很初级,根本就没有办法应用,不支持队列的爬虫,都是耍流氓. 所以我就先来举一个例子,看一下 ...

  7. python分布式爬虫框架_python之简单Scrapy分布式爬虫的实现

    分布式爬虫:爬虫共用同一个爬虫程序,即把同一个爬虫程序同时部署到多台电脑上运行,这样可以提高爬虫速度. 在默认情况下,scrapy爬虫是单机爬虫,只能在一台电脑上运行,因为爬虫调度器当中的队列queu ...

  8. 调用本地html_requests-html:最简单的爬虫框架,看完你就会了

    很多朋友都听说过Python的大名,而Python也拥有众多的爬虫框架,其中最简单的莫过于requests-html了.它和著名的网络请求库requests是同一个作者,着重于XML数据提取,可以说是 ...

  9. python爬虫框架排行榜-哪种Python框架适合你?简单介绍几种主流Python框架

    众所周知,Python开发框架大大减少了开发者不必要的重复劳动,提高了项目开发效率的同时,还使得创建的程序更加稳定.目前比较主流的Python框架都有哪些呢?一般大家用的比较多的是Django.Fla ...

最新文章

  1. VDI序曲二十 桌面虚拟化和RemoteApp集成到SharePoint 2010里
  2. 百度地图API详解之公交导航
  3. zabbix添加对web页面url的状态监控
  4. mongodb空间查询之查询单位
  5. Java系统变量之System.getenv()和System.getProperty()
  6. 在OSX中制作加密压缩文件
  7. 关闭(杀死)8080端口
  8. [译]5 Mac OS X RSS Readers Worth Giving a Shot
  9. 【操作系统】进程的状态与转换
  10. 利用CSS实现悬停下拉菜单
  11. vscode多开远程链接矩池云服务器
  12. linux 下安装gsl
  13. vs strncpy运行出错_日志VS网络数据,谁能做好全链路监控?
  14. 请求帮助--访问被拒绝:“Interop.jmail”
  15. 解析oracle sqllder日志,sqlloader 参数
  16. 小米pro 笔记本 计算机,小米笔记本Pro 15
  17. 一键登录163邮箱方法
  18. 词干提取算法Porter Stemming Algorithm解读
  19. 大数据时代的 10 个重大变化
  20. 荣耀 MagicBook pro 拆机图及硬盘安装过程

热门文章

  1. 【python】多进程共享变量
  2. 小程序web开发框架-weweb介绍
  3. 在线答题系统开发经验mysql,php
  4. PHPExcel处理导入导出图片,链接
  5. Cent OS – Tomcat 7 - 集群
  6. 编译后的boost库命名方式
  7. 2010年5月21日 下雨了
  8. 从春晚说起:总有一种无耻让我们泪流满面
  9. jquery之hide()用法详解
  10. mysql 随机数范围取值