Maison > développement back-end > Golang > le corps du texte

Explication détaillée du problème d'erreur d'ajout lorsque Go a une concurrence élevée !

藏色散人
Libérer: 2022-10-31 16:14:41
avant
2962 Les gens l'ont consulté

Cet article est écrit par la colonne tutoriel golang pour vous présenter les erreurs occasionnelles dans la méthode d'ajout lorsque go est hautement simultané. J'espère que cela sera utile aux amis qui en ont besoin !

Contexte

Lors de la mise en œuvre des exigences de transcodage d'images, il est nécessaire de prendre en charge jusqu'à 500 images après le téléchargement et la conversion des formats

Si vous téléchargez et transcodez un par un, cela prendra trop de temps et vous devrez l'utiliser ; goroutine pour implémenter 500 images. Après téléchargement simultané, transcodage simultané

Cependant, lors de l'auto-test, il a été découvert que seulement 499 images ou moins ont été converties après le téléchargement (à condition que tous les téléchargements et transcodages aient réussi

) ;

Ensuite, démarrez le processus d'impression des journaux pour trouver les bugs.

Dépannage

Étant donné que la synchronisation est utilisée pendant la simultanéité pour attendre la fin de toutes les coroutines, j'ai d'abord pensé qu'il y avait un problème avec l'attente asynchrone de synchronisation ;

J'ai imprimé le journal et j'ai constaté que 500 téléchargements avaient été exécutés normalement après le téléchargement. a été terminée, l'exécution s'est poursuivie L'opération de transcodage élimine les problèmes d'attente asynchrone de synchronisation

Le code est le suivant :

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("下载转码!")
//...
Copier après la connexion

Le journal est le suivant :

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   开始转码!
Copier après la connexion

Imprimez des journaux plus détaillés pour dépanner la logique dans la boucle de plage ;

À la fin d'une seule boucle for Ajouter un journal :

log.Error("下载协程结束: ", len(*successFiles))
Copier après la connexion

J'ai trouvé un journal spécial :

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
Copier après la connexion

La longueur est de 65 les deux fois et la longueur de la tranche n'a pas changé lorsque la méthode d'ajout de tranche est exécutée deux fois en même temps. , un échec se produira. La cause du problème est trouvée ;

Résolvez le problème

Utilisez l'index de tranche pour l'affectation, n'utilisez plus l'ajout

Le code de réparation est le suivant :

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() // 阻塞,等待完成
Copier après la connexion
 ;

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:juejin.im
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!