Golang Go语言中 Goroutine 如何并行抓取网页

发布于 1周前 作者 zlyuanteng 来自 Go语言

在写一道公司的题目,完成一个爬虫,题目要求之一是

要求支持多 routine 并行抓取(注意:这里并不是指简单设置 GOMAXPROCS>1)

然后我就懵了,怎么样才是并行抓取?我现在只知道设置 runtime.GOMAXPROCS=N

设置 GOMAXPROCS 是并行抓取吗,为什么?

不是很明白出题人的意思...


Golang Go语言中 Goroutine 如何并行抓取网页
19 回复

就是写个任务调度框架吧😂

更多关于Golang Go语言中 Goroutine 如何并行抓取网页的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


  1. 这个 IO 密集型, 像 Node.js 这样单进程也可以完成的很好, Promise.map + concurrency
    2. golang: https://github.com/magicdawn/go-co/tree/master 用 task.map
    https://github.com/magicdawn/go-co/blob/master/task/map.go#L11

你的意思是: 可以提交很多个 routine, 然后设置 runtime.GOMAXPROCS=cpu 核心数, 但是这样是不行的, 会导致所有的 routine 都进行了 request
题目意思可能是: 只有那么几个 concurrency routine 在跑, 一个结束了, 开始处理新的

前面那一种是相当于 concurrency = Infinity


我是这么想的 我只开 8 个 routine,不停的从 channel/queue 里面读抓取的网址然后去爬它.

但是如果我不开 GOMAXPROCS,那么每一个瞬间,都最多只有一个 routine 在跑,这只是利用异步 IO 在并发.

但是只要我设置了 GOMAXPROCS,这些 routine 就会被调度到不同的线程->不同的 CPU,这样才是并行

所以这里并行的关键是设置 GOMAXPROCS 对吧,那题目说的不是简单设置 GOMAXPROCS,这才是让我困惑的地方,我以为有什么其他的方法来实现并行

开 N 个 gorutine ,读 chan 里的任务,就这么简单,什么第三方库都不用。
这么基础的东西还要来 V2EX 问?贵司心略宽啊。

不用管 GOMAXPROCS 的事,默认是 cpu 核数,会用上所有核心的了

对于有限长度的队列, 如 []int{ 1, 2, 3, 4 }
job 为 sleep i 秒, 使用并发为 2 的时候, 耗时为 6s(2 + 4)
https://github.com/magicdawn/go-co/blob/master/demo/map/main.go

长度变化的队列, 工作中碰到的都是
while true
拿出 1000 个
等待 1000 个以某个并发完成
continue
再不行, 将 async.parallelLimit 代码抄下来写一点

啊, 这种还是 nodejs 来的简单…


关于 GOMAXPROCS,版本不到 1.5

我厂有国内流量最大的 Go 项目

百度吧?

我的意思是,为什么你这都不会写还……

lz 的意思是,并行的关键就是简单设置 GOMAXPROCS ,你怎么看出来不会写


“爬虫: Goroutine 如何并行抓取网页”
“然后我就懵了,怎么样才是并行抓取?我现在只知道设置 runtime.GOMAXPROCS=N ”
我现在只知道设置
我现在只知道设置
我现在只知道设置

我是这样看出来不会写的。

就爬虫这个例子,不论 GOMAXPROCS 是 1 还是几,都能写出并行抓取的爬虫,因为主要工作都是 net poller 做的, goroutine 并不需要多少 cpu 时间片。
主要工作是网络 io 的场景, GOMAXPROCS 和并行没有关系。

楼主还不知道并发并行的区别

一年多前自己的实现是 buffer chan

在Go语言中,Goroutine 是实现并发执行的有效工具。要并行抓取网页,你可以利用 Goroutine 的轻量级和高效性,结合 net/http 包来发送 HTTP 请求。以下是一个简单的示例,展示了如何使用 Goroutine 并行抓取网页:

  1. 定义一个函数来抓取网页:这个函数会接收一个 URL,使用 http.Get 方法发送请求,并返回响应体内容。

  2. 使用 Goroutine 并行执行:在需要并行抓取的 URL 列表上迭代,为每个 URL 启动一个 Goroutine。

  3. 等待所有 Goroutine 完成:使用 sync.WaitGroup 来确保所有 Goroutine 在主函数退出前完成。

示例代码:

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
    "sync"
)

func fetchURL(url string, wg *sync.WaitGroup, results chan<- string) {
    defer wg.Done()
    resp, err := http.Get(url)
    if err != nil {
        results <- fmt.Sprintf("Failed to fetch %s: %v", url, err)
        return
    }
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        results <- fmt.Sprintf("Failed to read %s: %v", url, err)
        return
    }
    results <- string(body)
}

func main() {
    // URL 列表和 WaitGroup 初始化代码省略...
    // 使用 Goroutine 和 channel 收集结果...
}

这样,你就可以利用 Goroutine 的并发特性,高效地并行抓取多个网页。注意,实际应用中应添加错误处理、超时控制等,以提高程序的健壮性。

回到顶部