LoginSignup
2
2

More than 1 year has passed since last update.

Goで並行ダウンロードするならとりあえずこれ書いとけ

Last updated at Posted at 2022-07-11

ソースコード

package main

import (
	"context"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/url"
	"os"
	"strings"
	"sync"

	"golang.org/x/sync/semaphore"
)

func downloadParallel(urls []string) {
	var wg sync.WaitGroup
	var s = semaphore.NewWeighted(5) // 同時実行するgoroutineの数を指定
	for _, u := range urls {
		wg.Add(1)
		go downloadFromURL(u, &wg, s)
	}
	wg.Wait() // goroutineに投げた全ての処理が終了するまで待機
}

func downloadFromURL(_url string, wg *sync.WaitGroup, s *semaphore.Weighted) {
	defer wg.Done() // この関数の実行が終了したことをsync.WaitGroupに伝える
	if err := s.Acquire(context.Background(), 1); err != nil { // セマフォを1つロック
		return
	}
	defer s.Release(1) // この関数の実行完了時にセマフォを1つ解放

	u, err := url.Parse(_url)
	if err != nil {
		log.Fatal(err)
	}
	path := u.Path
	segments := strings.Split(path, "/")
	fileName := segments[len(segments)-1] // URLからファイル名を作成
	file, err := os.Create(fileName) // ファイル名からファイルを作成
	if err != nil {
		log.Fatal(err)
	}
	resp, err := http.Get(_url) // URLからレスポンスを取得
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()
	size, err := io.Copy(file, resp.Body) // 取得したレスポンスをファイルにコピー
	fmt.Printf("%s %dKB\n", fileName, size/1024)
	defer file.Close()
}

解説

downloadParallel関数にurlの入った配列を渡すと、並行ダウンロードしてくれます。
便宜上、semaphoreで同時に実行できるgoroutineの数を制限していますが、値をもっと大きくしても大丈夫です。(ていうか、もっと大きくしないと速さが実感できない)

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2