Golang download multiple files in parallel using goroutines

huangapple go评论69阅读模式
英文:

Golang download multiple files in parallel using goroutines

问题

使用goroutines并行下载和保存文件是可能的。在你的代码中,当你在download_file函数前面加上go命令时,它不起作用的原因是你没有等待goroutine完成。你可以使用sync.WaitGroup来等待所有的goroutine完成。下面是修改后的代码示例:

package main

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"sync"
)

const app_key string = "<app_key>"
const app_secret string = "<app_secret>"

var code string

type TokenResponse struct {
	AccessToken string `json:"access_token"`
}

type File struct {
	Path string
}

type FileListResponse struct {
	FileList []File `json:"contents"`
}

func download_file(file File, token TokenResponse, wg *sync.WaitGroup) {
	defer wg.Done()

	download_file := fmt.Sprintf("https://api-content.dropbox.com/1/files/dropbox/%s?access_token=%s", file.Path, token.AccessToken)

	resp, _ := http.Get(download_file)
	defer resp.Body.Close()

	filename := filepath.Base(file.Path)
	out, err := os.Create(filename)
	if err != nil {
		panic(err)
	}
	defer out.Close()

	io.Copy(out, resp.Body)
}

func main() {
	authorize_url := fmt.Sprintf("https://www.dropbox.com/1/oauth2/authorize?response_type=code&client_id=%s", app_key)

	// Get code
	fmt.Printf("1. Go to: %s\n", authorize_url)
	fmt.Println("2. Click 'Allow' (you might have to log in first)")
	fmt.Println("3. Copy the authorization code.")
	fmt.Printf("Enter the authorization code here: ")
	fmt.Scanf("%s", &code)
	// End get code

	// Get access token
	data := url.Values{}
	data.Add("code", code)
	data.Add("grant_type", "authorization_code")
	data.Add("client_id", app_key)
	data.Add("client_secret", app_secret)

	resp, _ := http.PostForm("https://api.dropbox.com/1/oauth2/token", data)
	defer resp.Body.Close()

	contents, _ := ioutil.ReadAll(resp.Body)

	var tr TokenResponse

	json.Unmarshal(contents, &tr)
	// End get access token

	// Get file list
	file_list_url := fmt.Sprintf("https://api.dropbox.com/1/metadata/dropbox/Camera Uploads?access_token=%s", tr.AccessToken)

	resp2, _ := http.Get(file_list_url)
	defer resp2.Body.Close()

	contents2, _ := ioutil.ReadAll(resp2.Body)

	var flr FileListResponse
	json.Unmarshal(contents2, &flr)
	// End get file list

	var wg sync.WaitGroup

	for i, file := range flr.FileList {
		wg.Add(1)
		go download_file(file, tr, &wg)

		if i >= 2 {
			break
		}
	}

	wg.Wait()
}

在修改后的代码中,我们使用了sync.WaitGroup来等待所有的goroutine完成。每个goroutine在完成下载和保存文件后,调用wg.Done()来通知WaitGroup完成一个goroutine的执行。在主函数中,我们使用wg.Wait()来等待所有的goroutine完成。这样就可以实现并行下载和保存文件的功能。

英文:

Is it possible to download and save files in parallel using goroutines?

Below is my code which downloads files from my dropbox:

package main
import (
&quot;encoding/json&quot;
&quot;fmt&quot;
&quot;io&quot;
&quot;io/ioutil&quot;
&quot;net/http&quot;
&quot;net/url&quot;
&quot;os&quot;
&quot;path/filepath&quot;
)
const app_key string = &quot;&lt;app_key&gt;&quot;
const app_secret string = &quot;&lt;app_secret&gt;&quot;
var code string
type TokenResponse struct {
AccessToken string `json:&quot;access_token&quot;`
}
type File struct {
Path string
}
type FileListResponse struct {
FileList []File `json:&quot;contents&quot;`
}
func download_file(file File, token TokenResponse) {
download_file := fmt.Sprintf(&quot;https://api-content.dropbox.com/1/files/dropbox/%s?access_token=%s&quot;, file.Path, token.AccessToken)
resp, _ := http.Get(download_file)
defer resp.Body.Close()
filename := filepath.Base(file.Path)
out, err := os.Create(filename)
if err != nil {
panic(err)
}
defer out.Close()
io.Copy(out, resp.Body)
}
func main() {
authorize_url := fmt.Sprintf(&quot;https://www.dropbox.com/1/oauth2/authorize?response_type=code&amp;client_id=%s&quot;, app_key)
// Get code
fmt.Printf(&quot;1. Go to: %s\n&quot;, authorize_url)
fmt.Println(&quot;2. Click &#39;Allow&#39; (you might have to log in first)&quot;)
fmt.Println(&quot;3. Copy the authorization code.&quot;)
fmt.Printf(&quot;Enter the authorization code here: &quot;)
fmt.Scanf(&quot;%s&quot;, &amp;code)
// End get code
// Get access token
data := url.Values{}
data.Add(&quot;code&quot;, code)
data.Add(&quot;grant_type&quot;, &quot;authorization_code&quot;)
data.Add(&quot;client_id&quot;, app_key)
data.Add(&quot;client_secret&quot;, app_secret)
resp, _ := http.PostForm(&quot;https://api.dropbox.com/1/oauth2/token&quot;, data)
defer resp.Body.Close()
contents, _ := ioutil.ReadAll(resp.Body)
var tr TokenResponse
json.Unmarshal(contents, &amp;tr)
// End get access token
// Get file list
file_list_url := fmt.Sprintf(&quot;https://api.dropbox.com/1/metadata/dropbox/Camera Uploads?access_token=%s&quot;, tr.AccessToken)
resp2, _ := http.Get(file_list_url)
defer resp2.Body.Close()
contents2, _ := ioutil.ReadAll(resp2.Body)
var flr FileListResponse
json.Unmarshal(contents2, &amp;flr)
// End get file list
for i, file := range flr.FileList {
download_file(file, tr)
if i &gt;= 2 {
break
}
}
}

It doesn't work when I prefix the download_file function with the go command.

go download_file(file, tr)

答案1

得分: 13

这是因为你的主 goroutine 正在退出。你需要添加一个 WaitGroup 来等待所有的 goroutine 退出。例如,

var wg sync.WaitGroup
for i, file := range flr.FileList {
wg.Add(1)
go download_file(file, tr, wg)
if i >= 2 {
break
}
}
wg.Wait()
...
func download_file(file File, token TokenResponse, wg sync.WaitGroup) {
...
wg.Done()
}
英文:

That's because your main goroutine is exiting. You need to add a WaitGroup to wait until all the goroutines exit. For example,

var wg sync.WaitGroup
for i, file := range flr.FileList {
wg.Add(1)
go download_file(file, tr, wg)
if i &gt;= 2 {
break
}
}
wg.Wait()
...
func download_file(file File, token TokenResponse, wg sync.WaitGroup) {
...
wg.Done()
}

答案2

得分: 0

这个项目可能会帮助你和其他想要在Go语言中实现并发的人:

这个想法是在Go语言中创建一个集群来执行并行任务。https://github.com/waqar-alamgir/mini-go-cluster

可以对源代码进行调整以实现并发下载文件。

英文:

This project might help you and others that are looking into achieving concurrency in Go:

Idea is to create a cluster in Go to execute parallel jobs. https://github.com/waqar-alamgir/mini-go-cluster

Source can be tweaked to download files concurrently.

huangapple
  • 本文由 发表于 2014年5月13日 23:10:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/23635070.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定