面试题答案
一键面试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)
}
fetchData
函数:- 这个函数负责从给定的
url
获取数据。 - 使用
http.Get
发起HTTP GET请求,如果请求出错,将错误发送到errorChan
,并通过defer wg.Done()
标记该协程任务完成。 - 如果请求成功,将读取到的数据(这里简单假设为字符串形式)发送到
resultChan
。
- 这个函数负责从给定的
main
函数:- 定义了要爬取的
urls
列表。 - 创建了
WaitGroup
、resultChan
和errorChan
。 - 遍历
urls
,为每个url
启动一个协程执行fetchData
函数,并使用wg.Add(1)
增加等待组计数。 - 使用一个单独的协程等待所有协程完成(
wg.Wait()
),然后关闭resultChan
和errorChan
。 - 通过
for...range
从resultChan
中接收数据,并添加到allData
切片中。 - 通过
for...range
从errorChan
中接收网络错误并打印。 - 最后,对
allData
中的数据进行汇总分析(这里只是简单打印)。
- 定义了要爬取的
这样既使用WaitGroup
管理了协程的并发,又处理了可能出现的网络错误,并且通过并发请求提高了整体效率。