>  기사  >  백엔드 개발  >  Go 동시성이 높을 때 추가 오류 문제에 대한 자세한 설명!

Go 동시성이 높을 때 추가 오류 문제에 대한 자세한 설명!

藏色散人
藏色散人앞으로
2022-10-31 16:14:413036검색

이 글은 golang 튜토리얼에서 go가 동시성이 높을 때 가끔 발생하는 추가 방법에 대해 소개하기 위해 작성되었습니다. 다음은 방법을 자세히 설명하는 것이 필요한 친구들에게 도움이 되기를 바랍니다.

Background

이미지 트랜스코딩 요구 사항을 구현할 때 형식을 다운로드하고 변환한 후 최대 500개의 이미지를 지원해야 합니다.

하나씩 다운로드하여 트랜스코딩하면 시간이 너무 오래 걸리므로 사용해야 합니다. 500개의 이미지를 동시 다운로드 후 동시 트랜스코딩

그러나 자체 테스트 중에 다운로드 후 499개 이하의 이미지만 변환된 것으로 나타났습니다(모든 다운로드 및 트랜스코딩이 성공한 조건에서).

그런 다음 버그를 찾기 위해 로그를 인쇄하는 프로세스를 시작하세요.

문제 해결

동시성에서는 모든 코루틴이 끝날 때까지 기다리기 때문에 처음에는 동기화 비동기 대기에 문제가 있는 줄 알았습니다.

로그를 인쇄해 보니 다운로드가 정상적으로 실행된 것을 발견했습니다. 완료, 실행 계속됨 트랜스코딩 작업은 동기화 비동기 대기 문제를 제거합니다.

코드는 다음과 같습니다.

import (
   "github.com/satori/go.uuid"
   "sync"
)
func downloadFiles(nWait *sync.WaitGroup, urls []interface{}, successFiles *[]string, failedFiles *[]string) {
   // 遍历 urls 进行下载
   for _, value := range urls {
   go func(value interface{}) {
   defer nWait.Done()                                                     // 执行结束,协程减 1
   fullname := config.TranscodeDownloadPath + "/" + uuid.NewV4().String() // 需要确保文件名的唯一性 (防止不同用户同一时间操作了同一文件,导致转码失败)
   err := utils.DownloadCeph(value.(string), fullname)                    // 下载文件
   // 下载文件状态记录
   if err != nil {
   *failedFiles = append(*failedFiles, fullname)
   } else {
   *successFiles = append(*successFiles, fullname)
   }
   }(value)
   }
}
// 前端传入的图片 url
strUrlList := req["strUrlList"]
// 初始化变量
nWait := sync.WaitGroup{}          // 多协程异步等待
var successFiles []string  // 下载成功文件
var failedFiles []string           // 下载失败文件
// 遍历 strUrlList 进行下载
log.Error("开始下载!长度:", len(strUrlList))
nWait.Add(len(strUrlList)) // 等待协程数
downloadFiles(&nWait, strUrlList, &successFiles, &failedFiles)
nWait.Wait() // 阻塞,等待完成
log.Error("下载结束!长度:", len(successFiles))
//...
log.Error("下载转码!")
//...

로그는 다음과 같습니다.

2022-10-29 21:28:51.996 ERROR   services/tools.go:149   开始下载!长度:500
2022-10-29 21:28:52.486 ERROR   services/tools.go:153   下载结束!长度:499
2022-10-29 21:28:52.486 ERROR   services/tools.go:155   开始转码!

for range 루프 내의 논리 문제를 해결하려면 더 자세한 로그를 인쇄하세요.

단일 for 루프의 끝에서 로그 추가:

log.Error("下载协程结束: ", len(*successFiles))

특수 로그 발견:

2022-10-29 21:40:38.407 ERROR   services/tools.go:35    下载协程结束: 63
2022-10-29 21:40:38.407 ERROR   services/tools.go:35    下载协程结束: 64
2022-10-29 21:40:38.407 ERROR   services/tools.go:35    下载协程结束: 65
2022-10-29 21:40:38.407 ERROR   services/tools.go:35    下载协程结束: 65
2022-10-29 21:40:38.408 ERROR   services/tools.go:35    下载协程结束: 66
2022-10-29 21:40:38.408 ERROR   services/tools.go:35    下载协程结束: 67

길이는 두 번 모두 65이고, 슬라이스 추가 방법을 동시에 두 번 실행했을 때 슬라이스 길이는 변경되지 않았습니다. , 문제의 원인이 하나 발견됩니다.

문제 해결

할당에 슬라이스 인덱스를 사용하고 더 이상 추가를 사용하지 마세요.

import (
   "github.com/satori/go.uuid"
   "sync"
)
func downloadFiles(nWait *sync.WaitGroup, urls []interface{}, successFiles *[]string, failedFiles *[]string) {
   // 遍历 urls 进行下载
   for index, value := range urls {
   go func(index int, value interface{}) {
   defer nWait.Done()                                                     // 执行结束,协程减 1
   fullname := config.TranscodeDownloadPath + "/" + uuid.NewV4().String() // 需要确保文件名的唯一性 (防止不同用户同一时间操作了同一文件,导致转码失败)
   err := utils.DownloadCeph(value.(string), fullname)                    // 下载文件
   // 下载文件状态记录
   if err != nil {
   (*failedFiles)[index] = fullname
   } else {
   (*successFiles)[index] = fullname
   }
   }(index, value)
   }
}
// 前端传入的图片 url
strUrlList := req["strUrlList"]
// 初始化变量
nWait := sync.WaitGroup{}                                        // 多协程异步等待
successFiles := make([]string, len(strUrlList), len(strUrlList)) // 下载成功文件
failedFiles := make([]string, len(strUrlList), len(strUrlList))  // 下载失败文件
// 遍历 strUrlList 进行下载
nWait.Add(len(strUrlList)) // 等待协程数
downloadFiles(&nWait, strUrlList, &successFiles, &failedFiles)
nWait.Wait() // 阻塞,等待完成

위 내용은 Go 동시성이 높을 때 추가 오류 문제에 대한 자세한 설명!의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 juejin.im에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제