背景说明

假设有一个分布式文件系统,现需要从该系统中并发下载一部分文件到本地机器。

已知该文件系统的部分节点ip, 以及需要下载的文件fileID列表,并能通过这些信息来拼接下载地址。

其中节点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")
)

// 逐行读取文件内容
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
}

// 实现单个文件的下载
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()

  // 从文件中读取节点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)

  // 每个goroutine处理一个文件的下载
  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)
  }

  // 等待每个文件下载的完成,并检查超时
  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
    }
  }
}

小结

下载时没有用到默认的http Client, 并指定了超时时间;

下载文件时调用了系统调用, goroutine会被挂起;

下载文件完成后会唤醒被挂起的goroutine, 该goroutine执行完后面的代码后便退出;

全局超时控制,超时后主线程退出。

以上这篇golang并发下载多个文件的方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。

标签:
golang,并发,下载,文件

免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件! 如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
桃源资源网 Design By www.nqtax.com

评论“golang并发下载多个文件的方法”

暂无“golang并发下载多个文件的方法”评论...

《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线

暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。

艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。

《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。