golang并發(fā)下載多個(gè)文件的方法
背景說(shuō)明
假設(shè)有一個(gè)分布式文件系統(tǒng),現(xiàn)需要從該系統(tǒng)中并發(fā)下載一部分文件到本地機(jī)器。
已知該文件系統(tǒng)的部分節(jié)點(diǎn)ip, 以及需要下載的文件fileID列表,并能通過(guò)這些信息來(lái)拼接下載地址。
其中節(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í)沒(méi)有用到默認(rèn)的http Client, 并指定了超時(shí)時(shí)間;
下載文件時(shí)調(diào)用了系統(tǒng)調(diào)用, goroutine會(huì)被掛起;
下載文件完成后會(huì)喚醒被掛起的goroutine, 該goroutine執(zhí)行完后面的代碼后便退出;
全局超時(shí)控制,超時(shí)后主線程退出。
以上這篇golang并發(fā)下載多個(gè)文件的方法就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- 使用google-perftools優(yōu)化nginx在高并發(fā)時(shí)的性能的教程(完整版)
- Golang極簡(jiǎn)入門教程(三):并發(fā)支持
- Go語(yǔ)言并發(fā)技術(shù)詳解
- Go語(yǔ)言并發(fā)模型的2種編程方案
- GO語(yǔ)言并發(fā)編程之互斥鎖、讀寫鎖詳解
- Go語(yǔ)言如何并發(fā)超時(shí)處理詳解
- 如何利用Golang寫出高并發(fā)代碼詳解
- golang實(shí)現(xiàn)并發(fā)數(shù)控制的方法
- 詳解Golang 中的并發(fā)限制與超時(shí)控制
- golang中sync.Map并發(fā)創(chuàng)建、讀取問(wèn)題實(shí)戰(zhàn)記錄
- Go 并發(fā)實(shí)現(xiàn)協(xié)程同步的多種解決方法
- 在Go中構(gòu)建并發(fā)TCP服務(wù)器
- Go 并發(fā)控制context實(shí)現(xiàn)原理剖析(小結(jié))
- Go并發(fā)調(diào)用的超時(shí)處理的方法
- golang 并發(fā)安全Map以及分段鎖的實(shí)現(xiàn)方法
- Golang 實(shí)現(xiàn)分片讀取http超大文件流和并發(fā)控制
- golang gin 框架 異步同步 goroutine 并發(fā)操作
- Go并發(fā)4種方法簡(jiǎn)明講解
相關(guān)文章
一文帶你掌握Golang中panic與recover的使用方法
這篇文章主要介紹了Golang中panic與recover的作用和使用方法,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,需要的小伙伴可以參考一下2023-04-04
go語(yǔ)言題解LeetCode453最小操作次數(shù)使數(shù)組元素相等
這篇文章主要為大家介紹了go語(yǔ)言題解LeetCode453最小操作次數(shù)使數(shù)組元素相等示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12
golang在GRPC中設(shè)置client的超時(shí)時(shí)間
這篇文章主要介紹了golang在GRPC中設(shè)置client的超時(shí)時(shí)間,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-04-04
GO使用socket和channel實(shí)現(xiàn)簡(jiǎn)單控制臺(tái)聊天室
今天小編給大家分享一個(gè)簡(jiǎn)單的聊天室功能,聊天室主要功能是用戶可以加入離開(kāi)聊天室,實(shí)現(xiàn)思路也很簡(jiǎn)單明了,下面小編給大家?guī)?lái)了完整代碼,感興趣的朋友跟隨小編一起看看吧2021-12-12
goframe重寫FastAdmin后端實(shí)現(xiàn)實(shí)例詳解
這篇文章主要為大家介紹了goframe重寫FastAdmin后端實(shí)現(xiàn)實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12

