Aller : notes d'optimisation simples
Lorsque votre VPS exécute plusieurs applications de service, mais que l'une d'elles occupe parfois toutes les ressources, ce qui rend impossible l'accès au serveur via ssh. Vous passez à l’utilisation d’un cluster Kubernetes et définissez des limites pour toutes les applications. Nous avons ensuite vu certaines applications redémarrer alors que le OOM-killer résolvait le problème de « fuite » de mémoire.
Bien sûr, le MOO n'est pas toujours un problème de fuite, cela peut aussi être un dépassement de ressources. Les problèmes de fuite sont très probablement causés par des erreurs de programme. Le sujet dont nous parlons aujourd'hui est de savoir comment éviter cette situation.
Une consommation excessive de ressources nuit au portefeuille, ce qui signifie que nous devons prendre des mesures immédiates.
Ne pas optimiser prématurément
Parlons maintenant de l'optimisation. J'espère que vous comprendrez pourquoi nous ne devrions pas optimiser prématurément !
Premièrement, l'optimisation peut être un travail inutile. Parce que nous devrions d’abord étudier l’ensemble de l’application, et votre code ne sera probablement pas le goulot d’étranglement. Ce dont nous avons besoin, ce sont des résultats rapides, MVP (Minimum Viable Product, minimum viable product), et ensuite nous examinerons ses problèmes. Deuxièmement, l'optimisation doit être basée sur une base. C’est-à-dire que chaque optimisation doit être basée sur un benchmark, et nous devons prouver quel profit elle nous apporte. Troisièmement, l'optimisation peut apporter de la complexité. Ce que vous devez savoir, c'est que la plupart des optimisations rendent votre code moins lisible. Vous devez trouver cet équilibre.
Suggestions d'optimisation
Nous donnons maintenant quelques suggestions pratiques selon la classification standard des entités dans Go.
1. Tableaux et tranches
Allouez de la mémoire pour les tranches à l'avance
Essayez d'utiliser le troisième paramètre : <code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #000000;background: rgba(14, 210, 247, 0.15);"><span style="font-size: 15px;">make([]T, 0, len)</span>
make([]T, 0, len)
Si le nombre exact d'éléments n'est pas connu et la tranche est de courte durée Oui, vous pouvez allouer une taille plus grande pour garantir que la tranche ne s'agrandit pas pendant l'exécution.
N'oubliez pas d'utiliser copyEssayez de ne pas utiliser append lors de la copie, par exemple lors de la fusion de deux tranches ou plus.
Itération correcteUne tranche contenant de nombreux éléments ou de gros éléments, utilisez pour pour obtenir un seul élément. De cette façon, les duplications inutiles seront évitées.
Multiplexage de tranchesSi une opération est effectuée sur la tranche entrante et renvoie un résultat modifié, nous pouvons le renvoyer. Cela évite une nouvelle allocation de mémoire.
🎜Ne laissez pas une partie inutilisée de la tranche
Si vous devez couper un petit morceau de la tranche et l'utiliser uniquement, la partie principale de la tranche sera également conservée. L'approche correcte consiste à utiliser une nouvelle copie de cette petite tranche et à lancer l'ancienne tranche au GC.
2. Épissage correct des chaînes
Si l'épissage des chaînes peut être effectué en une seule instruction, utilisez <code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #000000;background: rgba(14, 210, 247, 0.15);"><span style="font-size: 15px;">+</span>
操作符。如果需要在循环中执行此操作,使用 <span style="font-size: 15px;">string.Builder</span>
,并使用它的 <span style="font-size: 15px;">Grow</span>
方法预先指定 <span style="font-size: 15px;">Builder</span>
的大小,减少内存分配次数。
转换优化
string 和 []byte 在底层结构上非常相近,有时这两种类型之间可以通过强转换来避免内存分配。
字符串驻留
可以池化字符串,从而帮助编译器只存储一次相同的字符串。
避免分配
我们可以使用 map(级联)而不是复合键,我们可以使用字节切片。尽量不使用 <span style="font-size: 15px;">fmt</span>
+ opérateur. Si vous devez le faire en boucle, utilisez
🎜string.Builder🎜
🎜 et utilisez son 🎜🎜Grow🎜
🎜 la méthode est pré-spécifiée🎜🎜Builder🎜
🎜 taille pour réduire le nombre d'allocations de mémoire. 🎜🎜🎜Optimisation de la conversion🎜🎜🎜string et []byte sont très similaires dans la structure sous-jacente, et parfois une conversion forte peut être utilisée entre ces deux types pour éviter l'allocation de mémoire. 🎜🎜🎜String résident🎜🎜🎜 peut regrouper des chaînes, aidant ainsi le compilateur à stocker la même chaîne une seule fois. 🎜🎜🎜Éviter l'allocation🎜🎜🎜Nous pouvons utiliser map(cascade) au lieu de clés composites, nous pouvons utiliser des tranches d'octets. Essayez de ne pas utiliser 🎜🎜 fmt 🎜
🎜 package, car toutes ses méthodes utilisent la réflexion. 🎜🎜3. Structure
Évitez de copier de grandes structures
Nous comprenons que les petites structures ne comportent pas plus de 4 champs et pas plus d'une taille de mot machine.
Quelques scénarios de copie typiques
Projeté sur l'interface Réception et envoi de canaux -
Remplacement d'éléments dans la carte Ajouter des éléments aux tranches Itération (plage)
Évitez d'accéder aux champs de structure via des pointeurs
Le déréférencement coûte cher et nous devrions le faire le moins possible, surtout dans les boucles. Il perd également la possibilité d'utiliser des registres rapides.
Manipulation des petites structures
Ce travail est optimisé par l'éditeur, ce qui veut dire qu'il est bon marché.
Utilisez l'alignement pour réduire la taille de la structure
Nous pouvons réduire la taille de la structure elle-même en alignant la structure (en les disposant dans le bon ordre en fonction de la taille des champs).
4. Fonctions
Utilisez des fonctions en ligne ou inlinez-les vous-même
Essayez d'écrire de petites fonctions qui peuvent être intégrées par le compilateur, ce sera plus rapide, encore plus rapide que d'intégrer vous-même le code dans la fonction. Cela est particulièrement vrai pour les chemins chauds.
Lesquels ne seront pas en ligne
récupération bloc de sélection déclaration de type defer goroutine pour-gamme
raisonnable Choisissez judicieusement les paramètres de fonction
Essayez d'utiliser de petits paramètres car leur réplication sera optimisée. Essayez de maintenir la réplication et la croissance de la pile équilibrées sur la charge du GC. Évitez un grand nombre de paramètres et laissez votre programme utiliser des registres rapides (leur nombre est limité).
Valeurs de retour nommées
Cela semble être plus efficace que de déclarer ces variables dans le corps de la fonction.
Enregistrez les résultats intermédiaires
Aidez le compilateur à optimiser votre code, enregistrez les résultats intermédiaires, et il y aura ensuite plus d'options pour optimiser votre code.
Utilisez defer avec précaution
Essayez de ne pas utiliser defer, ou du moins ne l'utilisez pas en boucle.
Aide au chemin chaud
Évitez d'allouer de la mémoire dans le chemin chaud, en particulier les objets de courte durée. Créez les branches les plus courantes (si, switch)
5. Map
Allocation de mémoire à l'avance
Identique à la tranche, lors de l'initialisation de la carte, spécifiez sa taille.
Utiliser des structures vides comme valeurs
struct{} n'est rien (ne prend pas de mémoire), il est donc très avantageux de l'utiliser lors du passage de signaux par exemple.
Effacer la carte
la carte ne peut que croître, pas rétrécir. Lorsque nous devons réinitialiser la carte, supprimer tous ses éléments ne nous aidera pas.
Essayez de ne pas utiliser de pointeurs dans les clés et les valeurs
Si la carte ne contient pas de pointeurs, alors le GC ne perdra pas de temps précieux dessus. Les chaînes utilisent également des pointeurs, vous devez donc utiliser des tableaux d'octets au lieu de chaînes comme clés.
Réduire le nombre de modifications
De même, nous ne voulons pas utiliser de pointeurs, mais nous pouvons utiliser une combinaison de carte et de tranche, en stockant les clés dans la carte et les valeurs dans la tranche. De cette façon, nous pouvons modifier la valeur sans restrictions.
6. Interface
Calculer l'allocation de mémoire
N'oubliez pas que lorsque vous souhaitez attribuer une valeur à une interface, vous devez d'abord la copier quelque part, puis y coller le pointeur. La clé est de copier. Il s'avère que le coût du boxing et du déballage de l'interface sera à peu près le même que celui de l'allocation de la taille de la structure.
Choisir le type optimal
Dans certains cas, il n'y a pas d'allocation lors du boxing et du unboxing des interfaces. Par exemple, des valeurs petites ou booléennes pour les variables et les constantes, des structures avec un champ simple, des pointeurs (y compris carte, canal, fonction)
Évitez l'allocation de mémoire
Comme ailleurs, essayez d'éviter les allocations inutiles. Par exemple attribuer une interface à une autre au lieu de boxer deux fois.
À utiliser uniquement en cas de besoin
Évitez d'utiliser des interfaces dans les paramètres de fonction fréquemment appelés et renvoyez les résultats. Nous n'avons pas besoin d'opérations de déballage supplémentaires. Réduisez la fréquence d’utilisation des appels de méthode d’interface car cela empêche l’inline.
7. Pointeurs, canaux, vérifications de limites
Évitez les déréférencements inutiles
Surtout dans les boucles car cela s'avère trop coûteux. Le déréférencement est quelque chose que nous ne voulons pas faire à nos propres frais.
L'utilisation des canaux est inefficace
La synchronisation des canaux est plus lente que les autres méthodes primitives de synchronisation. De plus, plus il y a de cas sélectionnés, plus notre programme sera lent. Cependant, select, case et default ont été optimisés.
Évitez les contrôles de limites inutiles
Cela coûte également cher et nous devrions l'éviter. Par exemple, vérifiez (obtenez) l’index de tranche maximum une seule fois, et non plusieurs fois. Il est préférable d'essayer d'opter pour l'option extrême maintenant.
Résumé
Tout au long de cet article, nous avons vu certaines des mêmes règles d'optimisation.
Aidez le compilateur à prendre la bonne décision et il vous remerciera. Allouez de la mémoire au moment de la compilation, utilisez des résultats intermédiaires et essayez de garder votre code lisible.
Je réitère que pour une optimisation implicite, les benchmarks sont obligatoires. Si quelque chose qui a fonctionné hier ne fonctionnera pas demain car le compilateur change trop rapidement entre les versions, et vice versa.
N'oubliez pas d'utiliser les outils d'analyse et de suivi intégrés de 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!

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

AI Hentai Generator
Générez AI Hentai gratuitement.

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Dans Go, les messages WebSocket peuvent être envoyés à l'aide du package gorilla/websocket. Étapes spécifiques : Établissez une connexion WebSocket. Envoyer un message texte : appelez WriteMessage(websocket.TextMessage,[]byte("message")). Envoyez un message binaire : appelez WriteMessage(websocket.BinaryMessage,[]byte{1,2,3}).

Dans Go, vous pouvez utiliser des expressions régulières pour faire correspondre les horodatages : compilez une chaîne d'expression régulière, telle que celle utilisée pour faire correspondre les horodatages ISO8601 : ^\d{4}-\d{2}-\d{2}T \d{ 2}:\d{2}:\d{2}(\.\d+)?(Z|[+-][0-9]{2}:[0-9]{2})$ . Utilisez la fonction regexp.MatchString pour vérifier si une chaîne correspond à une expression régulière.

Dans Go, le cycle de vie de la fonction comprend la définition, le chargement, la liaison, l'initialisation, l'appel et le retour ; la portée des variables est divisée en niveau de fonction et au niveau du bloc. Les variables d'une fonction sont visibles en interne, tandis que les variables d'un bloc ne sont visibles que dans le bloc. .

Les fuites de mémoire peuvent entraîner une augmentation continue de la mémoire du programme Go en : fermant les ressources qui ne sont plus utilisées, telles que les fichiers, les connexions réseau et les connexions à la base de données. Utilisez des références faibles pour éviter les fuites de mémoire et ciblez les objets pour le garbage collection lorsqu'ils ne sont plus fortement référencés. En utilisant go coroutine, la mémoire de la pile de coroutines sera automatiquement libérée à la sortie pour éviter les fuites de mémoire.

Go et le langage Go sont des entités différentes avec des caractéristiques différentes. Go (également connu sous le nom de Golang) est connu pour sa concurrence, sa vitesse de compilation rapide, sa gestion de la mémoire et ses avantages multiplateformes. Les inconvénients du langage Go incluent un écosystème moins riche que les autres langages, une syntaxe plus stricte et un manque de typage dynamique.

Consultez la documentation de la fonction Go à l'aide de l'EDI : passez le curseur sur le nom de la fonction. Appuyez sur la touche de raccourci (GoLand : Ctrl+Q ; VSCode : Après avoir installé GoExtensionPack, F1 et sélectionnez « Go:ShowDocumentation »).

Les tests unitaires des fonctions simultanées sont essentiels car cela permet de garantir leur comportement correct dans un environnement simultané. Des principes fondamentaux tels que l'exclusion mutuelle, la synchronisation et l'isolement doivent être pris en compte lors du test de fonctions concurrentes. Les fonctions simultanées peuvent être testées unitairement en simulant, en testant les conditions de concurrence et en vérifiant les résultats.

Dans Golang, les wrappers d'erreurs vous permettent de créer de nouvelles erreurs en ajoutant des informations contextuelles à l'erreur d'origine. Cela peut être utilisé pour unifier les types d'erreurs générées par différentes bibliothèques ou composants, simplifiant ainsi le débogage et la gestion des erreurs. Les étapes sont les suivantes : Utilisez la fonction error.Wrap pour envelopper les erreurs d'origine dans de nouvelles erreurs. La nouvelle erreur contient des informations contextuelles de l'erreur d'origine. Utilisez fmt.Printf pour générer des erreurs encapsulées, offrant ainsi plus de contexte et de possibilités d'action. Lors de la gestion de différents types d’erreurs, utilisez la fonction erreurs.Wrap pour unifier les types d’erreurs.
