MST

星途 面试题库

面试题:Go的WaitGroup在复杂并发场景下的应用

假设你正在开发一个爬虫程序,需要从多个网页获取数据,每个网页的请求是一个协程。在获取完所有网页数据后,需要对数据进行汇总分析。请使用WaitGroup来管理这些协程的并发,并实现数据汇总的逻辑。注意,要处理可能出现的网络错误,并且要考虑如何提高整体的并发效率。
14.2万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试
package main

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

// 模拟从网页获取数据的函数
func fetchData(url string, wg *sync.WaitGroup, resultChan chan string, errorChan chan error) {
    defer wg.Done()
    resp, err := http.Get(url)
    if err != nil {
        errorChan <- err
        return
    }
    defer resp.Body.Close()

    // 这里简单读取响应内容为字符串,实际应用中可根据需求解析数据
    // 这里只是简单示例,实际可以使用io/ioutil.ReadAll或者bufio.Scanner等更合适的方式
    var data string
    // 假设这里有读取数据到data的逻辑
    resultChan <- data
}

func main() {
    urls := []string{
        "http://example.com",
        "http://another-example.com",
        // 更多URL
    }

    var wg sync.WaitGroup
    resultChan := make(chan string)
    errorChan := make(chan error)

    for _, url := range urls {
        wg.Add(1)
        go fetchData(url, &wg, resultChan, errorChan)
    }

    go func() {
        wg.Wait()
        close(resultChan)
        close(errorChan)
    }()

    var allData []string
    for result := range resultChan {
        allData = append(allData, result)
    }

    for err := range errorChan {
        fmt.Println("网络错误:", err)
    }

    // 这里开始进行数据汇总分析
    // 简单示例,打印获取到的数据
    fmt.Println("汇总数据:", allData)
}
  1. fetchData函数
    • 这个函数负责从给定的url获取数据。
    • 使用http.Get发起HTTP GET请求,如果请求出错,将错误发送到errorChan,并通过defer wg.Done()标记该协程任务完成。
    • 如果请求成功,将读取到的数据(这里简单假设为字符串形式)发送到resultChan
  2. main函数
    • 定义了要爬取的urls列表。
    • 创建了WaitGroupresultChanerrorChan
    • 遍历urls,为每个url启动一个协程执行fetchData函数,并使用wg.Add(1)增加等待组计数。
    • 使用一个单独的协程等待所有协程完成(wg.Wait()),然后关闭resultChanerrorChan
    • 通过for...rangeresultChan中接收数据,并添加到allData切片中。
    • 通过for...rangeerrorChan中接收网络错误并打印。
    • 最后,对allData中的数据进行汇总分析(这里只是简单打印)。

这样既使用WaitGroup管理了协程的并发,又处理了可能出现的网络错误,并且通过并发请求提高了整体效率。