Maison >développement back-end >Golang >Enregistrez un petit piège de Golang Recover
1.error
Golang est souvent critiqué pour son manque de gestion des exceptions puissante et pratique. Mécanisme, la plupart des langages de programmation de haut niveau, tels que Java, PHP, Python, etc., disposent d'un mécanisme de capture d'essai. Ce mécanisme de capture d'exception peut très facilement gérer diverses situations inattendues pouvant survenir pendant le fonctionnement du programme. À proprement parler, dans Go, les erreurs et les exceptions sont de deux types différents. Les erreurs font généralement référence à des erreurs logiques générées par le programme, ou à des situations inattendues, et les exceptions sont généralement des paniques, comme des coins marqués hors limites. , erreur de segmentation. Pour les erreurs, Golang adopte une méthode très primitive. Nous devons gérer manuellement chaque erreur qui peut survenir. Généralement, l'erreur sera renvoyée à l'appelant. La méthode d'écriture suivante est très courante dans Go :.
package mainimport ( "errors" "fmt")func main() { s, err := say() if err != nil { fmt.Printf("%s\n", err.Error()) } else { fmt.Printf("%s\n", s) }}func say() (string, error) { // do something return "", errors.New("something error")}复制代码Le plus gros problème avec cette façon d'écrire est que chaque erreur doit être jugée et traitée, ce qui est très fastidieux si nous utilisons le mécanisme try catch, nous pouvons gérer uniformément les erreurs qui peuvent survenir lorsque plusieurs appels de fonction sont appelés. , économisant un peu de code et de temps. Mais nous ne sommes pas ici pour discuter du mécanisme de gestion des exceptions et des erreurs de Go aujourd’hui. Nous en parlerons simplement brièvement ici.
2.panic
Généralement, les erreurs sont affichées et renvoyées explicitement par le programme, tandis que les exceptions sont souvent implicites et imprévisibles, comme le. code suivant :package mainimport "fmt"func main() { fmt.Printf("%d\n", cal(1,2)) fmt.Printf("%d\n", cal(5,2)) fmt.Printf("%d\n", cal(5,0)) //panic: runtime error: integer pide by zero fmt.Printf("%d\n", cal(9,5))}func cal(a, b int) int { return a / b}复制代码Une panique se produira lors de l'exécution du troisième calcul. Cette erreur entraînera la fermeture du programme et le code suivant ne pourra pas être exécuté. Bien sûr, on peut dire que ce type d’erreur est théoriquement prévisible et qu’il suffit de la gérer dans la fonction cal. Cependant, dans le développement réel, il peut y avoir de nombreux endroits où la panique se produit, et ce n'est pas quelque chose qui peut être vu d'un coup d'œil dans un service Web, une telle panique entraînera le blocage de l'ensemble du service Web. vers le haut, ce qui est particulièrement dangereux.
3.recover
Bien qu'il n'y ait pas de mécanisme de capture d'essai, Go a en fait un mécanisme de récupération similaire. La fonction est un peu plus faible et. l'utilisation est très simple. :package mainimport "fmt"func main() { fmt.Printf("%d\n", cal(1, 2)) fmt.Printf("%d\n", cal(5, 2)) fmt.Printf("%d\n", cal(5, 0)) fmt.Printf("%d\n", cal(9, 2))}func cal(a, b int) int { defer func() { if err := recover(); err != nil { fmt.Printf("%s\n", err) } }() return a / b}复制代码Tout d'abord, tout le monde doit comprendre le rôle de defer, en termes simples, il est similaire au destructeur orienté objet. Il sera exécuté à la fin de cette fonction. s'il se termine par la panique. Ainsi, chaque fois que la fonction cal se termine, elle vérifiera s'il y a une exception. Si cela se produit, nous pouvons la gérer, comme l'enregistrement des journaux, afin que le programme puisse continuer à s'exécuter.
4. Pièges à noter
Généralement, le mécanisme de récupération différée est souvent utilisé dans les applications de processus résidents, telles que les services Web In Go. À l'intérieur, chaque requête Web se verra attribuer une goroutine à traiter. Sans aucun traitement, si une certaine requête panique, l'ensemble du service sera suspendu. Ceci est inacceptable, il doit donc être utilisé dans les applications Web pour garantir. que même si une erreur se produit dans une requête, les autres requêtes ne seront pas affectées. Ici, j'utilise un petit morceau de code pour le simuler :package mainimport ( "fmt")func main() { requests := []int{12, 2, 3, 41, 5, 6, 1, 12, 3, 4, 2, 31} for n := range requests { go run(n) //开启多个协程 } for { select {} }}func run(num int) { //模拟请求错误 if num%5 == 0 { panic("请求出错") } fmt.Printf("%d\n", num)}复制代码Le code ci-dessus ne peut pas être exécuté complètement, car l'une des coroutines va inévitablement paniquer, provoquant le blocage de toute l'application. la coroutine arrête également de s'exécuter. La solution est la même que ci-dessus. Il suffit d'ajouter la récupération différée à la fonction d'exécution, et l'ensemble du programme sera très robuste, même en cas de panique, il sera exécuté complètement.
func run(num int) { defer func() { if err := recover();err != nil { fmt.Printf("%s\n", err) } }() if num%5 == 0 { panic("请求出错") } fmt.Printf("%d\n", num)}复制代码Le code ci-dessus n'est qu'une démonstration. Le vrai piège est le suivant : si vous démarrez d'autres coroutines dans la fonction run, la panique qui se produit dans cette coroutine ne peut pas être récupérée, et cela entraînera toujours l'exécution de l'ensemble du processus. hang. , nous avons modifié l'exemple ci-dessus :
func run(num int) { defer func() { if err := recover(); err != nil { fmt.Printf("%s\n", err) } }() if num%5 == 0 { panic("请求出错") } go myPrint(num)}func myPrint(num int) { if num%4 == 0 { panic("请求又出错了") } fmt.Printf("%d\n", num)}复制代码J'ai appelé une autre fonction via la coroutine dans la fonction run, et cette fonction paniquera également. Vous constaterez que le programme entier se bloque également. a recovery, cela n'a aucun effet, ce qui signifie que nous devons quand même ajouter recovery à la fonction myPrint. Mais si vous n'appelez pas la fonction myPrint à l'aide d'une coroutine, vous pouvez toujours capturer la récupération en l'appelant directement. Pour résumer, le mécanisme de récupération différée concerne uniquement la panique qui peut être générée par la fonction actuelle et la fonction directement appelée. Il ne peut pas gérer la panique des autres coroutines générées par son appel. essayez le mécanisme de capture.
En théorie, tous les endroits où les coroutines sont utilisées doivent être différés, afin de garantir que votre application est infaillible. Cependant, cela peut être déterminé en fonction de la situation réelle pendant le développement. affectent également les performances.
Il en va de même pour les services Web de Go. Le mécanisme de récupération par défaut ne peut capturer qu'une seule couche. Si vous utilisez d'autres coroutines dans le traitement de cette requête, vous devez être très prudent. l'intégralité du service Web se bloquera.
Enfin, pour résumer, bien que le mécanisme de gestion des exceptions de Go ne soit pas aussi efficace que celui de nombreux autres langages, il peut fondamentalement répondre aux besoins. Le responsable est actuellement en train d'améliorer cela et pourrait le voir dans Go2.
Recommandé : "tutoriel de langue go"
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!