英文:
Golang amazon s3 how can I upload images faster
问题
我有一些图片,我正在使用官方的Amazon S3包将它们上传到我的S3账户。我的图片通常大小在250-350 KB左右,所以是小图片,但是它们需要大约8或9秒才能上传,这似乎太长了。有没有什么建议可以提高上传速度?以下是我的代码,即使我将调整图像大小的代码去掉,上传仍然需要8或9秒。
func UploadStreamImage(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
var buff bytes.Buffer
wg := sync.WaitGroup{}
wg.Add(1)
go func() {
defer wg.Done()
var buf bytes.Buffer
sess, _ := session.NewSession(&aws.Config{
Region: aws.String("us-west-2"),
Credentials: credentials.NewStaticCredentials(aws_access_key_id, aws_secret_access_key, ""),
})
svc := s3.New(sess)
file, handler, err := r.FormFile("file")
if err != nil {
log_errors(" error on upload",err.Error(),w)
fmt.Println("Error Uploading Image")
return
}
defer file.Close()
img,err := imaging.Decode(file)
if err != nil {
print("Imaging Open error")
log_errors("Error decoding",err.Error(),w)
return
}
imgSize,err := strconv.Atoi(r.FormValue("imgsize"))
if err != nil {
println("Error converting to integer")
log_errors("Error converting to integer",err.Error(),w)
return
}
b := img.Bounds()
heightImg := b.Max.Y
widthImg := b.Max.X
// resize image
height := int(float64(heightImg) * .23)
width := int(float64(widthImg) * .23)
if imgSize < 401 {
height = int(float64(heightImg) * 1)
width = int(float64(widthImg) * 1)
} else if imgSize >= 401 && imgSize < 900 {
height = int(float64(heightImg) * .68)
width = int(float64(widthImg) * .68)
println("Middle Image")
} else if imgSize >= 900 && imgSize < 1300 {
height = int(float64(heightImg) * .45)
width = int(float64(widthImg) * .45)
} else if imgSize >= 1301 && imgSize < 1700 {
height = int(float64(heightImg) * .40)
width = int(float64(widthImg) * .40)
}
new_img := imaging.Resize(img,width,height, imaging.Lanczos)
// end resize
err = imaging.Encode(&buf,new_img, imaging.JPEG)
if err != nil {
log.Println(err)
log_errors(" error encoding file",err.Error(),w)
return
}
r := bytes.NewReader(buf.Bytes())
read_file,err := ioutil.ReadAll(r)
if err != nil {
fmt.Println("Error Reading file")
log_errors(" error reading file",err.Error(),w)
return
}
file.Read(read_file)
fileBytes := bytes.NewReader(read_file)
fileSize, err := buff.ReadFrom(fileBytes)
if err != nil {
log_errors(" error fileSize",err.Error(),w)
return
}
fileType := http.DetectContentType(read_file)
path := handler.Filename
params := &s3.PutObjectInput{
Bucket: aws.String("bucket name"),
Key: aws.String(path),
Body: fileBytes,
ContentLength: aws.Int64(fileSize),
ContentType: aws.String(fileType),
}
resp, err := svc.PutObject(params)
if err != nil {
fmt.Printf("bad response: %s", err)
log_errors("error in putObject",err.Error(),w)
return
}
fmt.Println(w,"Done")
}()
wg.Wait()
}
请注意,我只会翻译代码部分,不会回答关于翻译的问题。
英文:
I have some images that I am uploading to my s3 account using the official amazon s3 package . My images are typically around 250 - 350 KB so small images, however they take around 8 or 9 seconds to upload which seems excessive any suggestions on improving speed would be great. This is my code and if I take the resizing image code off it still takes a good 8 or 9 seconds still .
func UploadStreamImage(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
var buff bytes.Buffer
wg := sync.WaitGroup{}
wg.Add(1)
go func() {
defer wg.Done()
var buf bytes.Buffer
sess, _ := session.NewSession(&aws.Config{
Region: aws.String("us-west-2"),
Credentials: credentials.NewStaticCredentials(aws_access_key_id, aws_secret_access_key, ""),
})
svc := s3.New(sess)
file, handler, err := r.FormFile("file")
if err != nil {
log_errors(" error on upload",err.Error(),w)
fmt.Println("Error Uploading Image")
return
}
defer file.Close()
img,err := imaging.Decode(file)
if err != nil {
print("Imaging Open error")
log_errors("Error decoding",err.Error(),w)
return
}
imgSize,err := strconv.Atoi(r.FormValue("imgsize"))
if err != nil {
println("Error converting to integer")
log_errors("Error converting to integer",err.Error(),w)
return
}
b := img.Bounds()
heightImg := b.Max.Y
widthImg := b.Max.X
// resize image
height := int(float64(heightImg) * .23)
width := int(float64(widthImg) * .23)
if imgSize < 401 {
height = int(float64(heightImg) * 1)
width = int(float64(widthImg) * 1)
} else if imgSize >= 401 && imgSize < 900 {
height = int(float64(heightImg) * .68)
width = int(float64(widthImg) * .68)
println("Middle Image")
} else if imgSize >= 900 && imgSize < 1300 {
height = int(float64(heightImg) * .45)
width = int(float64(widthImg) * .45)
} else if imgSize >= 1301 && imgSize < 1700 {
height = int(float64(heightImg) * .40)
width = int(float64(widthImg) * .40)
}
new_img := imaging.Resize(img,width,height, imaging.Lanczos)
// end resize
err = imaging.Encode(&buf,new_img, imaging.JPEG)
if err != nil {
log.Println(err)
log_errors(" error encoding file",err.Error(),w)
return
}
r := bytes.NewReader(buf.Bytes())
read_file,err := ioutil.ReadAll(r)
if err != nil {
fmt.Println("Error Reading file")
log_errors(" error reading file",err.Error(),w)
return
}
file.Read(read_file)
fileBytes := bytes.NewReader(read_file)
fileSize, err := buff.ReadFrom(fileBytes)
if err != nil {
log_errors(" error fileSize",err.Error(),w)
return
}
fileType := http.DetectContentType(read_file)
path := handler.Filename
params := &s3.PutObjectInput{
Bucket: aws.String("bucket name"),
Key: aws.String(path),
Body: fileBytes,
ContentLength: aws.Int64(fileSize),
ContentType: aws.String(fileType),
}
resp, err := svc.PutObject(params)
if err != nil {
fmt.Printf("bad response: %s", err)
log_errors("error in putObject",err.Error(),w)
return
}
fmt.Println(w,"Done")
}()
wg.Wait()
}
答案1
得分: 4
"提高速度?"这是一个主观的问题,取决于许多因素,如服务器上行链路、客户端上行链路等。
相反,我将提供改进你的代码片段的建议:
- 让我们从
sync.WaitGroup
开始 - 根据你的代码流程,我没有看到它的好处,你只是创建并等待goroutine完成。不要为了使用而使用WaitGroup
。提示:不要为了追求新功能而使用它,而是在需要时使用它。 - 当你可以不使用
bytes.Buffer
和Reader
时,不要创建多个。例如,在调整大小后获取文件大小,只需使用buf.Len()
。 - 如果你想将AWS上传分担出去,将上传代码部分提取到单独的
func
中,并作为goroutine调用。
我已经更新了你的代码片段(我没有测试你的代码,所以请根据需要进行修复/改进):
func UploadStreamImage(w http.ResponseWriter, r *http.Request) {
file, handler, err := r.FormFile("file")
if err != nil {
log_errors(" error on upload", err.Error(), w)
fmt.Println("Error Uploading Image")
return
}
defer file.Close()
// 建议:你可以通过字节计算文件大小,而不是从表单中获取;因为调整大小后图像会改变
imgSize, err := strconv.Atoi(r.FormValue("imgsize"))
if err != nil {
println("Error converting to integer")
log_errors("Error converting to integer", err.Error(), w)
return
}
img, err := imaging.Decode(file)
if err != nil {
print("Imaging Open error")
log_errors("Error decoding", err.Error(), w)
return
}
b := img.Bounds()
heightImg := b.Max.Y
widthImg := b.Max.X
// 调整大小
height := int(float64(heightImg) * .23)
width := int(float64(widthImg) * .23)
if imgSize < 401 {
height = int(float64(heightImg) * 1)
width = int(float64(widthImg) * 1)
} else if imgSize >= 401 && imgSize < 900 {
height = int(float64(heightImg) * .68)
width = int(float64(widthImg) * .68)
println("Middle Image")
} else if imgSize >= 900 && imgSize < 1300 {
height = int(float64(heightImg) * .45)
width = int(float64(widthImg) * .45)
} else if imgSize >= 1301 && imgSize < 1700 {
height = int(float64(heightImg) * .40)
width = int(float64(widthImg) * .40)
}
new_img := imaging.Resize(img, width, height, imaging.Lanczos)
// 结束调整大小
var buf bytes.Buffer
err = imaging.Encode(&buf, new_img, imaging.JPEG)
if err != nil {
log.Println(err)
log_errors(" error encoding file", err.Error(), w)
return
}
fileType := http.DetectContentType(buf.Bytes())
fileSize := buf.Len()
path := handler.Filename
params := &s3.PutObjectInput{
Bucket: aws.String("bucket name"),
Key: aws.String(path),
Body: bytes.NewReader(buf.Bytes()),
ContentLength: aws.Int64(fileSize),
ContentType: aws.String(fileType),
}
resp, err := svc.PutObject(params)
if err != nil {
fmt.Printf("bad response: %s", err)
log_errors("error in putObject", err.Error(), w)
return
}
fmt.Println("Done", resp)
}
英文:
Improving speed?
this is subjective one; depends on many factors such as server uplink, client uplink, etc.
Instead, I will provide my inputs to improve your code snippets:
- Let's start with
sync.WaitGroup
- I do not see a benefit as per your code flow, you just create and wait for goroutine to complete. Instead use without WaitGroup.Tip:
Do not use feature for sake/buzz; use it when needed. - Do not create multiple
bytes.Buffer
andReader
, when you can accomplish without it. For e.g. getting fileSize after the resize, just dobuf.Len()
. - If you want to offload the AWS upload then extract upload code part into separate
func
and call it as goroutine.
I have updated your code snippet (I have not tested your code, so please fix/improve it as required):
func UploadStreamImage(w http.ResponseWriter, r *http.Request) {
file, handler, err := r.FormFile("file")
if err != nil {
log_errors(" error on upload", err.Error(), w)
fmt.Println("Error Uploading Image")
return
}
defer file.Close()
// Suggestion: You can calculate the file size from bytes.
// instead getting it from form; since after resize image will change
imgSize, err := strconv.Atoi(r.FormValue("imgsize"))
if err != nil {
println("Error converting to integer")
log_errors("Error converting to integer", err.Error(), w)
return
}
img, err := imaging.Decode(file)
if err != nil {
print("Imaging Open error")
log_errors("Error decoding", err.Error(), w)
return
}
b := img.Bounds()
heightImg := b.Max.Y
widthImg := b.Max.X
// resize image
height := int(float64(heightImg) * .23)
width := int(float64(widthImg) * .23)
if imgSize < 401 {
height = int(float64(heightImg) * 1)
width = int(float64(widthImg) * 1)
} else if imgSize >= 401 && imgSize < 900 {
height = int(float64(heightImg) * .68)
width = int(float64(widthImg) * .68)
println("Middle Image")
} else if imgSize >= 900 && imgSize < 1300 {
height = int(float64(heightImg) * .45)
width = int(float64(widthImg) * .45)
} else if imgSize >= 1301 && imgSize < 1700 {
height = int(float64(heightImg) * .40)
width = int(float64(widthImg) * .40)
}
new_img := imaging.Resize(img, width, height, imaging.Lanczos)
// end resize
var buf bytes.Buffer
err = imaging.Encode(&buf, new_img, imaging.JPEG)
if err != nil {
log.Println(err)
log_errors(" error encoding file", err.Error(), w)
return
}
fileType := http.DetectContentType(buf.Bytes())
fileSize := buf.Len()
path := handler.Filename
params := &s3.PutObjectInput{
Bucket: aws.String("bucket name"),
Key: aws.String(path),
Body: bytes.NewReader(buf.Bytes()),
ContentLength: aws.Int64(fileSize),
ContentType: aws.String(fileType),
}
resp, err := svc.PutObject(params)
if err != nil {
fmt.Printf("bad response: %s", err)
log_errors("error in putObject", err.Error(), w)
return
}
fmt.Println("Done", resp)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论