Go 每日一題:併發下載與合併
答案
實現思路:
-
文件分割: 將目標文件分割成多個大小相等的塊(例如 10MB / 塊)。
-
併發下載: 爲每個文件塊創建一個 goroutine,每個 goroutine 負責下載對應塊的內容並保存到臨時文件中。
-
同步與合併: 使用 channel 來同步所有 goroutine 的下載進度,並在所有塊下載完成後,按順序合併所有臨時文件,最終得到完整的原始文件。
代碼示例:
package main
import (
"fmt"
"io"
"net/http"
"os"
"sync"
)
func main() {
url := "https://example.com/large_file.zip" // 目標文件 URL
filePath := "large_file.zip" // 下載後的文件名
chunkSize := 10 * 1024 * 1024 // 每個塊的大小:10MB
downloadFile(url, filePath, chunkSize)
}
func downloadFile(url, filePath string, chunkSize int) {
// 獲取文件大小
resp, _ := http.Head(url)
fileSize := int(resp.ContentLength)
// 計算塊的數量
chunkCount := (fileSize + chunkSize - 1) / chunkSize
// 創建 channel 用於同步下載進度
done := make(chan bool, chunkCount)
// 使用 WaitGroup 等待所有 goroutine 完成
var wg sync.WaitGroup
wg.Add(chunkCount)
// 併發下載文件塊
for i := 0; i < chunkCount; i++ {
go func(i int) {
defer wg.Done()
start := i * chunkSize
end := (i + 1) * chunkSize
if end > fileSize {
end = fileSize
}
downloadChunk(url, filePath, i, start, end)
done <- true
}(i)
}
// 等待所有塊下載完成
go func() {
wg.Wait()
close(done)
}()
// 合併文件塊
mergeChunks(filePath, chunkCount)
}
func downloadChunk(url, filePath string, chunkId, start, end int) {
// 創建 HTTP 請求
req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("Range", fmt.Sprintf("bytes=%d-%d", start, end-1))
// 發送請求並下載文件塊
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
// 創建臨時文件
tmpFile, _ := os.Create(fmt.Sprintf("%s.part%d", filePath, chunkId))
defer tmpFile.Close()
// 將下載內容寫入臨時文件
io.Copy(tmpFile, resp.Body)
}
func mergeChunks(filePath string, chunkCount int) {
// 創建最終文件
finalFile, _ := os.Create(filePath)
defer finalFile.Close()
// 按順序合併所有臨時文件
for i := 0; i < chunkCount; i++ {
tmpFileName := fmt.Sprintf("%s.part%d", filePath, i)
tmpFile, _ := os.Open(tmpFileName)
defer tmpFile.Close()
io.Copy(finalFile, tmpFile)
os.Remove(tmpFileName) // 刪除臨時文件
}
}
考點分析:
-
GMP 模型: 代碼中使用 goroutine 來實現併發下載,充分利用了 Golang 的多核優勢。
-
Channel: 使用 channel 來同步下載進度,確保所有塊下載完成後再進行合併操作。
-
WaitGroup: 使用 WaitGroup 來等待所有 goroutine 完成,避免主線程提前退出。
-
錯誤處理: 實際應用中需要添加更完善的錯誤處理機制。
總結:
這道面試題考察了候選人對 Golang 併發機制的理解和應用能力,以及解決實際問題的能力。一個優秀的答案應該清晰地描述實現思路,並使用簡潔高效的代碼進行實現。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/Ee2fbSqqqDRE7-vBjpR1mg