MST

星途 面试题库

面试题:Go的Goroutine与通道在高并发场景下的资源管理

在一个高并发的Web爬虫场景中,使用Goroutine和通道来管理并发请求。每个Goroutine负责爬取一个网页,通道用于传递网页URL和爬取结果。但由于资源限制,同一时间只能有10个Goroutine在运行。如何设计这个系统以确保资源的合理利用和程序的健壮性,详细说明设计思路和关键代码实现。
34.1万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 任务队列:使用通道来创建一个任务队列,用于存放需要爬取的网页URL。
  2. 工作池:限制同时运行的Goroutine数量为10,形成一个工作池。每个Goroutine从任务队列中获取URL,爬取网页并将结果通过另一个通道返回。
  3. 结果收集:使用一个结果通道来收集各个Goroutine爬取的结果。
  4. 资源管理:确保在所有任务完成后,能够正确关闭所有通道,避免死锁和资源泄漏。

关键代码实现

package main

import (
    "fmt"
    "sync"
)

// 模拟爬取网页的函数
func crawl(url string) string {
    // 实际爬取逻辑,这里简单返回URL
    return "Crawled: " + url
}

func worker(taskChan <-chan string, resultChan chan<- string, wg *sync.WaitGroup) {
    defer wg.Done()
    for url := range taskChan {
        result := crawl(url)
        resultChan <- result
    }
}

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

    const maxWorkers = 10
    taskChan := make(chan string)
    resultChan := make(chan string)
    var wg sync.WaitGroup

    // 创建工作池
    for i := 0; i < maxWorkers; i++ {
        wg.Add(1)
        go worker(taskChan, resultChan, &wg)
    }

    // 提交任务
    go func() {
        for _, url := range urls {
            taskChan <- url
        }
        close(taskChan)
    }()

    // 收集结果
    go func() {
        wg.Wait()
        close(resultChan)
    }()

    // 输出结果
    for result := range resultChan {
        fmt.Println(result)
    }
}
  1. crawl 函数:模拟实际的网页爬取逻辑,返回爬取结果。
  2. worker 函数:每个Goroutine执行的函数,从 taskChan 中获取URL,调用 crawl 函数爬取网页,并将结果发送到 resultChan
  3. main 函数
    • 初始化URL列表。
    • 创建任务通道 taskChan 和结果通道 resultChan
    • 创建工作池,启动10个Goroutine作为工作者。
    • 将任务发送到 taskChan 并关闭通道。
    • 等待所有工作者完成任务后关闭 resultChan
    • resultChan 中读取并输出结果。