Golang实现简单爬虫框架(4)——队列实现并发任务调度
前言
在上一篇文章《Golang实现简单爬虫框架(3)——简单并发版》中我们实现了一个最简单并发爬虫,调度器为每一个Request
创建一个goroutine
,每个goroutine
往Worker
队列中分发任务,发完就结束。所有的Worker
都在抢一个channel
中的任务。但是这样做还是有些许不足之处,比如控制力弱:所有的Worker在抢同一个channel
中的任务,我们没有办法控制给哪一个worker任务。
其实我们可以自己做一个任务分发的机制,我们来决定分发给哪一个Worker
注意:本次并发是在上一篇文章简单并发实现的基础上修改,所以没有贴出全部代码,只是贴出部分修改部分,要查看完整项目代码,可以查看上篇文章,或者从github下载项目源代码查看
1、项目架构
在上一篇文章实现简单并发的基础上,我们修改下Scheduler
的任务分发机制
- 当
Scheduler
接收到一个Request
后,不能直接发给Worker
,也不能为每个Request
创建一个goroutine
,所以这里使用一个Request队列 - 同时我们想对
Worker
实现一个更多的控制,可以决定把任务分发给哪一个Worker
,所以这里我们还需要一个Worker
队列 - 当有了
Request
和Worker
,我们就可以把选择的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)——队列实现并发任务调度相关推荐
- Golang实现简单爬虫框架(5)——项目重构与数据存储
前言 在上一篇文章<Golang实现简单爬虫框架(4)--队列实现并发任务调度>中,我们使用用队列实现了任务调度,接下来首先对两种并发方式做一个同构,使代码统一.然后添加数据存储模块. 注 ...
- python爬虫网站简单_Python爬虫之简单爬虫框架实现
简单爬虫框架实现 目录 框架流程 调度器 url管理器 网页下载器 网页解析器 数据处理器 具体演示效果 框架流程 调度器 #导入模块 import Url_Manager import parser ...
- golang爬虫框架colly简单介绍
colly一款快速优雅的golang爬虫框架,简单易用,功能完备. colly 官网地址:http://go-colly.org/ colly github地址:github.com/gocolly/ ...
- 非零基础自学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 ...
- autoload.php beanbun_Beanbun: 简单开放的 PHP 爬虫框架
Beanbun Beanbun 是用 PHP 编写的多进程网络爬虫框架,具有良好的开放性.高可扩展性. 项目地址:github.com/kiddyuchin.- 文档地址:beanbun.org 由来 ...
- nodejs和python爬虫 哪个好_简单好用的nodejs 爬虫框架分享
这个就是一篇介绍爬虫框架的文章,开头就不说什么剧情了.什么最近一个项目了,什么分享新知了,剧情是挺好,但介绍的很初级,根本就没有办法应用,不支持队列的爬虫,都是耍流氓. 所以我就先来举一个例子,看一下 ...
- python分布式爬虫框架_python之简单Scrapy分布式爬虫的实现
分布式爬虫:爬虫共用同一个爬虫程序,即把同一个爬虫程序同时部署到多台电脑上运行,这样可以提高爬虫速度. 在默认情况下,scrapy爬虫是单机爬虫,只能在一台电脑上运行,因为爬虫调度器当中的队列queu ...
- 调用本地html_requests-html:最简单的爬虫框架,看完你就会了
很多朋友都听说过Python的大名,而Python也拥有众多的爬虫框架,其中最简单的莫过于requests-html了.它和著名的网络请求库requests是同一个作者,着重于XML数据提取,可以说是 ...
- python爬虫框架排行榜-哪种Python框架适合你?简单介绍几种主流Python框架
众所周知,Python开发框架大大减少了开发者不必要的重复劳动,提高了项目开发效率的同时,还使得创建的程序更加稳定.目前比较主流的Python框架都有哪些呢?一般大家用的比较多的是Django.Fla ...
最新文章
- VDI序曲二十 桌面虚拟化和RemoteApp集成到SharePoint 2010里
- 百度地图API详解之公交导航
- zabbix添加对web页面url的状态监控
- mongodb空间查询之查询单位
- Java系统变量之System.getenv()和System.getProperty()
- 在OSX中制作加密压缩文件
- 关闭(杀死)8080端口
- [译]5 Mac OS X RSS Readers Worth Giving a Shot
- 【操作系统】进程的状态与转换
- 利用CSS实现悬停下拉菜单
- vscode多开远程链接矩池云服务器
- linux 下安装gsl
- vs strncpy运行出错_日志VS网络数据,谁能做好全链路监控?
- 请求帮助--访问被拒绝:“Interop.jmail”
- 解析oracle sqllder日志,sqlloader 参数
- 小米pro 笔记本 计算机,小米笔记本Pro 15
- 一键登录163邮箱方法
- 词干提取算法Porter Stemming Algorithm解读
- 大数据时代的 10 个重大变化
- 荣耀 MagicBook pro 拆机图及硬盘安装过程