Go 每日一題:併發下載與合併

答案

實現思路:

  1. 文件分割: 將目標文件分割成多個大小相等的塊(例如 10MB / 塊)。

  2. 併發下載: 爲每個文件塊創建一個 goroutine,每個 goroutine 負責下載對應塊的內容並保存到臨時文件中。

  3. 同步與合併: 使用 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) // 刪除臨時文件
 }
}

考點分析:

總結:

這道面試題考察了候選人對 Golang 併發機制的理解和應用能力,以及解決實際問題的能力。一個優秀的答案應該清晰地描述實現思路,並使用簡潔高效的代碼進行實現。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/Ee2fbSqqqDRE7-vBjpR1mg