背景說明
假設(shè)有一個(gè)分布式文件系統(tǒng),現(xiàn)需要從該系統(tǒng)中并發(fā)下載一部分文件到本地機(jī)器。
已知該文件系統(tǒng)的部分節(jié)點(diǎn)ip, 以及需要下載的文件fileID列表,并能通過這些信息來拼接下載地址。
其中節(jié)點(diǎn)ip列表保存在xx_node.txt, 要下載的fileID保存在xx_fileID.txt中。
代碼示例
package main
import (
"bufio"
"flag"
"fmt"
"io"
"math/rand"
"net/http"
"os"
"time"
)
var (
clustername = flag.String("clustername", "c1", "download clustername")
)
// 逐行讀取文件內(nèi)容
func ReadLines(fpath string) []string {
fd, err := os.Open(fpath)
if err != nil {
panic(err)
}
defer fd.Close()
var lines []string
scanner := bufio.NewScanner(fd)
for scanner.Scan() {
lines = append(lines, scanner.Text())
}
if err := scanner.Err(); err != nil {
fmt.Fprintln(os.Stderr, err)
}
return lines
}
// 實(shí)現(xiàn)單個(gè)文件的下載
func Download(clustername string, node string, fileID string) string {
nt := time.Now().Format("2006-01-02 15:04:05")
fmt.Printf("[%s]To download %s\n", nt, fileID)
url := fmt.Sprintf("http://%s/file/%s", node, fileID)
fpath := fmt.Sprintf("/yourpath/download/%s_%s", clustername, fileID)
newFile, err := os.Create(fpath)
if err != nil {
fmt.Println(err.Error())
return "process failed for " + fileID
}
defer newFile.Close()
client := http.Client{Timeout: 900 * time.Second}
resp, err := client.Get(url)
defer resp.Body.Close()
_, err = io.Copy(newFile, resp.Body)
if err != nil {
fmt.Println(err.Error())
}
return fileID
}
func main() {
flag.Parse()
// 從文件中讀取節(jié)點(diǎn)ip列表
nodelist := ReadLines(fmt.Sprintf("%s_node.txt", *clustername))
if len(nodelist) == 0 {
return
}
// 從文件中讀取待下載的文件ID列表
fileIDlist := ReadLines(fmt.Sprintf("%s_fileID.txt", *clustername))
if len(fileIDlist) == 0 {
return
}
ch := make(chan string)
// 每個(gè)goroutine處理一個(gè)文件的下載
r := rand.New(rand.NewSource(time.Now().UnixNano()))
for _, fileID := range fileIDlist {
node := nodelist[r.Intn(len(nodelist))]
go func(node, fileID string) {
ch - Download(*clustername, node, fileID)
}(node, fileID)
}
// 等待每個(gè)文件下載的完成,并檢查超時(shí)
timeout := time.After(900 * time.Second)
for idx := 0; idx len(fileIDlist); idx++ {
select {
case res := -ch:
nt := time.Now().Format("2006-01-02 15:04:05")
fmt.Printf("[%s]Finish download %s\n", nt, res)
case -timeout:
fmt.Println("Timeout...")
break
}
}
}
小結(jié)
下載時(shí)沒有用到默認(rèn)的http Client, 并指定了超時(shí)時(shí)間;
下載文件時(shí)調(diào)用了系統(tǒng)調(diào)用, goroutine會(huì)被掛起;
下載文件完成后會(huì)喚醒被掛起的goroutine, 該goroutine執(zhí)行完后面的代碼后便退出;
全局超時(shí)控制,超時(shí)后主線程退出。
以上這篇golang并發(fā)下載多個(gè)文件的方法就是小編分享給大家的全部內(nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
您可能感興趣的文章:- golang語言實(shí)現(xiàn)的文件上傳與文件下載功能示例
- Golang實(shí)現(xiàn)異步上傳文件支持進(jìn)度條查詢的方法
- Golang+Android基于HttpURLConnection實(shí)現(xiàn)的文件上傳功能示例
- golang簡單獲取上傳文件大小的實(shí)現(xiàn)代碼
- 如何使用大學(xué)教育郵箱下載golang等軟件(推薦)
- 解決 Golang VS Code 插件下載安裝失敗的問題
- golang實(shí)現(xiàn)http server提供文件下載功能
- Golang 使用http Client下載文件的實(shí)現(xiàn)方法
- 下載golang.org/x包的操作方法
- golang實(shí)現(xiàn)的文件上傳下載小工具