【发布时间】:2019-10-01 15:53:01
【问题描述】:
我正在尝试将目录上传到 Amazon S3 存储桶。但是,上传目录的唯一方法是遍历目录内的所有文件并逐个上传。
我正在使用 Go 来遍历目录中的文件。但是,对于我遍历的每个文件,我想派生一个上传文件的 goroutine,而主线程遍历目录中的下一个元素并派生另一个 goroutine 以上传相同的文件。
知道如何使用 Goroutines 和 Channels 并行上传目录中的所有文件吗?
修改后的代码 sn-p 实现了一个 goroutine 和一个并行上传文件的通道。但我不确定这是否是正确的实现方式。
func uploadDirToS3(dir string, svc *s3.S3) {
fileList := []string{}
filepath.Walk(dir, func(path string, f os.FileInfo, err error) error {
fmt.Println("PATH ==> " + path)
fileList = append(fileList, path)
return nil
})
for _, pathOfFile := range fileList[1:] {
channel := make(chan bool)
go uploadFiletoS3(pathOfFile, svc, channel)
<-channel
}
}
func uploadFiletoS3(path string, svc *s3.S3, channel chan bool) {
file, err := os.Open(path)
if err != nil {
fmt.Println(err)
}
defer file.Close()
fileInfo, _ := file.Stat()
size := fileInfo.Size()
buffer := make([]byte, size)
file.Read(buffer)
fileBytes := bytes.NewReader(buffer)
fileType := http.DetectContentType(buffer)
s3Path := file.Name()
params := &s3.PutObjectInput{
Bucket: aws.String("name-of-bucket"),
Key: aws.String(s3Path),
Body: fileBytes,
ContentLength: aws.Int64(size),
ContentType: aws.String(fileType),
}
resp, err := svc.PutObject(params)
if err != nil {
fmt.Println(err)
}
fmt.Printf("response %s", awsutil.StringValue(resp))
close(channel)
}
关于如何更好地实现这一点的任何想法?我研究了 WaitGroups,但出于某种原因,我发现 Channels 在这种情况下更容易理解和实现。
【问题讨论】:
-
是的,您可以将
for循环的内容放入 goroutine 中(但请确保在循环内制作pathOfFile的本地副本或将其作为参数传递给 goroutine 函数)。您可能想要使用sync.WaitGroup,这样您就可以等待它们全部完成(或不完成——这取决于您的程序的结构)。此外,您不需要将文件读入缓冲区。可以在PutObjectInput中设置file为Body的值 -
不幸的是,在当前代码中,您还没有实现任何并发。做好功课,学习 Go 并发模式,尝试一些东西,遇到困难,我们会帮助你。 google.com/search?q=go+concurrency+patterns
-
“对于我遍历的每个文件,我想分拆一个上传文件的 goroutine”,所以实现它。您当前的代码块,因为它是单线程的。 Tour of Go 涵盖了 Goroutines、通道和其他基本概念。
-
@AndySchweig 所以我修改了代码以实现通道而不是 WaitGroup。但是,我不完全确定这是否是正确的方法。文件仍在上传,代码正在运行,但不确定它是否并行运行。
-
@mh-cbon 刚刚使用 Goroutines 和 Channels 实现了这一点。不确定这是否是正确的方法。如果我能得到你的建议,那就太好了。
标签: amazon-web-services go amazon-s3 concurrency channels