面试题答案
一键面试核心代码逻辑
package main
import (
"fmt"
"sync"
)
// 模拟从API获取数据的函数
func fetchDataFromAPI(apiURL string, resultChan chan<- string, wg *sync.WaitGroup) {
defer wg.Done()
// 这里实际应是HTTP请求等获取数据操作,为简单模拟直接返回固定字符串
data := "Data from " + apiURL
resultChan <- data
}
func main() {
apiURLs := []string{"api1.com", "api2.com", "api3.com"}
var wg sync.WaitGroup
resultChan := make(chan string, len(apiURLs))
for _, url := range apiURLs {
wg.Add(1)
go fetchDataFromAPI(url, resultChan, &wg)
}
go func() {
wg.Wait()
close(resultChan)
}()
var mergedData string
for data := range resultChan {
mergedData += data + " "
}
fmt.Println("Merged Data:", mergedData)
}
设计思路
-
函数设计:
fetchDataFromAPI
函数模拟从API获取数据。它接收API的URL、一个用于发送结果的通道resultChan
以及一个sync.WaitGroup
指针。该函数在完成数据获取(这里是简单模拟)后,通过通道发送数据,并调用wg.Done()
表示任务完成。
-
并发处理:
- 在
main
函数中,遍历apiURLs
列表,为每个API URL启动一个新的goroutine来调用fetchDataFromAPI
函数,实现并发获取数据。通过wg.Add(1)
增加等待组的计数,确保所有goroutine都完成任务。
- 在
-
通道使用:
- 创建一个带缓冲的通道
resultChan
,缓冲大小为API的数量,用于接收各个goroutine获取的数据。这样可以避免在发送数据时阻塞,提高并发效率。 - 使用一个匿名goroutine,在所有
fetchDataFromAPI
任务完成(通过wg.Wait()
判断)后,关闭resultChan
。这样在for... range
循环中可以安全地迭代通道中的所有数据,直到通道关闭。
- 创建一个带缓冲的通道
-
合并数据:
- 在
main
函数的for... range
循环中,从resultChan
通道读取数据,并将其合并到mergedData
字符串中,最终输出合并后的数据。
- 在
-
并发安全:
- 使用
sync.WaitGroup
来协调各个goroutine的完成,确保在所有数据获取完成后才关闭通道并处理合并数据,避免数据竞争等并发安全问题。同时,通道本身是类型安全的,在多goroutine间传递数据时不会出现数据混乱的情况。
- 使用