1. Plusieurs concepts importants sur une grande concurrence
1.1 synchrone et asynchrone
Tout d'abord, la synchronisation et les asynchrones mentionnés ici se réfèrent ici aux aspects de la fonction / de la méthode.
De toute évidence, un appel synchrone attendra le retour de la méthode, et un appel asynchrone reviendra instantanément, mais un appel asynchrone reviendra instantanément ne signifie pas que votre tâche est terminée. Il configurera un fil en arrière-plan pour continuer la tâche.
1.2 concurrence et parallélisme
La concurrence et le parallélisme sont similaires en apparence externe. Comme le montre la figure, le parallélisme est lorsque deux tâches sont effectuées simultanément, tandis que la concurrence consiste à effectuer une tâche à la fois, puis à passer à une autre tâche. Par conséquent, un seul CPU ne peut pas être parallèle, il ne peut être que de la concurrence.
1.3 Zone critique
La zone critique est utilisée pour représenter une ressource publique ou des données partagées. Il peut être utilisé par plusieurs threads, mais un seul thread peut l'utiliser à la fois. Une fois la ressource de zone critique occupée, d'autres fils doivent attendre s'ils souhaitent utiliser cette ressource.
1.4 Blocage et non bloquant
Le blocage et le non-blocage décrivent généralement l'influence mutuelle entre plusieurs threads. Par exemple, si un thread occupe la ressource de zone critique, alors tous les autres threads qui ont besoin de cette ressource doivent attendre dans cette zone critique, et l'attente entraînera la suspension du fil. C'est un blocage. Pour le moment, si le fil qui occupe la ressource ne veut pas libérer la ressource, tous les autres threads bloquant dans ce domaine critique ne peuvent pas fonctionner.
Le non-blocage permet à plusieurs threads d'entrer dans la zone critique en même temps
Par conséquent, la performance du blocage n'est généralement pas très bonne. Selon les statistiques générales, si un thread est suspendu au niveau du système d'exploitation et a fait un changement de contexte, il faut généralement 80 000 cycles de temps pour ce faire.
1,5 impasse, faim, serrure en direct
La soi-disant impasse fait référence à un blocage causé par des ressources concurrentes ou à communiquer entre elles pendant le processus d'exécution de deux processus ou plus. Sans forces externes, ils ne pourront pas avancer. À l'heure actuelle, le système est appelé impasse ou le système a une impasse. Ces processus qui s'attendent toujours les uns aux autres sont appelés processus de blocage. Tout comme les voitures de l'image ci-dessous veulent avancer, mais personne ne peut avancer.
Cependant, bien que l'impasse est un mauvais phénomène, c'est un problème statique. Une fois qu'une impasse a eu lieu, le processus est bloqué et le taux d'occupation du processeur est également 0. Il n'occupera pas le CPU, il sera appelé. Relativement parlant, il est relativement facile de découvrir et d'analyser.
Le verrou vivant correspond à l'impasse.
Live Lock signifie que les choses 1 peuvent utiliser des ressources, mais cela permet à d'autres choses d'utiliser d'abord les ressources; Les choses 2 peuvent utiliser des ressources, mais cela permet également à d'autres choses d'utiliser les ressources en premier, donc les deux ont été humbles et ne peuvent pas utiliser les ressources.
Par exemple, c'est comme si vous rencontriez quelqu'un dans la rue, qui marche dans la direction opposée à vous et vous rencontrant de front, vous voulez tous vous laisser partir. Vous avez déménagé à gauche et il a déménagé à gauche, mais les deux ne pouvaient toujours pas y aller. À l'heure actuelle, vous vous déplacez vers la droite et il se déplace vers la droite et continuez de cette manière.
Lorsqu'un thread obtient une ressource, il constate que d'autres threads pensent également à cette ressource car ils n'ont pas obtenu toutes les ressources, donc pour éviter les délais de location, ils abandonnent toutes les ressources qu'ils détiennent. Si un autre fil fait la même chose, ils ont besoin des mêmes ressources, comme une ressource, B détient B la ressource B, et après avoir abandonné la ressource, une ressource obtient B, et B obtient une ressource, et cela est répété, une serrure vivante se produit.
Les serrures en direct sont plus difficiles à détecter que les impasses, car les serrures en direct sont un processus dynamique.
La faim signifie qu'un ou plusieurs threads ne peuvent pas obtenir les ressources requises pour diverses raisons, ce qui les rend incapables d'exécuter.
1.6 Niveau de concurrence
Niveaux de concurrence: blocage et non bloquant (le non-blocage est divisé en barrière, sans verrouillage et sans attente)
1.6.1 Blocage
Lorsqu'un thread entre dans la section critique, d'autres fils doivent attendre
1.6.2 Accessibilité
Par rapport à la planification non bloquante, le blocage de blocage est une stratégie pessimiste, qui estime que la modification des données ensemble est susceptible de rendre les données mauvaises. Au lieu de bloquer la planification, il s'agit d'une stratégie optimiste, qui estime que la modification des données ne peut pas nécessairement rendre les données mauvaises. Cependant, il s'agit d'une stratégie d'entrée large et de sortie stricte. Lorsqu'il constate qu'un processus a une concurrence de données et des conflits dans le domaine critique, la méthode de planification sans barrière fera reculer les données.
Dans cette méthode de planification sans barrière, tous les threads équivaut à prendre un instantané d'un système. Ils continueront d'essayer de prendre les instantanés jusqu'à ce qu'ils soient valables.
1.6.3 Lockless
C'est accessible
Assurez-vous qu'il y a un fil qui peut gagner
Par rapport à l'accessibilité, l'accessibilité ne garantit pas que les opérations peuvent être terminées en cas de concurrence, car s'il trouve des conflits dans chaque opération, il continuera d'essayer. Si les fils de la zone critique interfèrent les uns avec les autres, cela fera coincé tous les fils dans la zone critique, puis les performances du système auront un grand impact.
Lockless ajoute une nouvelle condition pour s'assurer qu'un fil peut gagner chaque compétition, ce qui résout le problème de la consommation de barrière. Au moins, il garantit que tous les fils s'exécutent en douceur.
Le code suivant est un code de calcul typique sans verrouillage en java
Lockless est commun à Java
while (! atomicvar.compareAndset (localvar, localvar + 1)) {localvar = atomicvar.get (); }1.6.4 pas d'attente
Sans verrouillage
Tous les threads doivent être complétés dans une étape limitée
Pas de faim
Tout d'abord, la prémisse de No Waiting est sur la base de Lock. Free sans verrouillage garantit qu'il doit y avoir une entrée et une sortie dans la zone critique. Cependant, si la priorité de l'entrée est très élevée, certains fils avec une faible priorité dans la zone critique peuvent avoir faim et ne peuvent pas quitter la zone critique. Ensuite, aucune attente ne résoudra ce problème, ce qui garantit que tous les fils doivent être complétés dans une étape limitée, et naturellement il n'y a pas de faim.
Aucune attente n'est le plus haut niveau de parallélisme, ce qui peut permettre à ce système d'atteindre l'état optimal.
Cas typiques sans attendre:
S'il n'y a que des threads de lecture et pas de threads de thread, cela doit être sans attendre.
S'il y a à la fois des threads de lecture et des threads d'écriture, et avant chaque thread d'écriture, copiez les données, puis modifiez la copie au lieu de modifier les données d'origine, car il n'y a pas de conflit dans la modification de la copie, le processus de modification est également sans attendre. La synchronisation finale est uniquement de remplacer les données écrites.
Étant donné que l'exigence sans attente est relativement élevée et qu'il est difficile à mettre en œuvre, sans serrure sera utilisé plus largement.
2. Deux lois importantes sur le parallélisme
Les deux lois sont liées au ratio d'accélération
2.1 Loi d'Amdahl
Définissez la formule de calcul et la limite supérieure théorique du rapport d'accélération après la parallélisation des systèmes en série
Définition du ratio d'accélération: rapport d'accélération = temps du système consommé avant l'optimisation / temps du système consommé après optimisation
Par exemple:
Ratio d'accélération = temps du système consommé avant l'optimisation / temps du système consommé après optimisation = 500/400 = 1,25
Ce théorème montre que l'augmentation du nombre de processeurs CPU ne joue pas nécessairement un rôle efficace dans l'augmentation de la proportion de modules parallèles dans le système. Ce n'est qu'en augmentant raisonnablement le nombre de processeurs parallèles que le ratio d'accélération maximum peut être obtenu avec le plus petit investissement.
2.2 La loi de Gustafson
Expliquez la relation entre le nombre de processeurs, le rapport série et le rapport d'accélération
Ensuite, le rapport d'accélération = NF (N-1) // Le processus de dérivation est omis
Tant qu'il y a une parallélisation suffisante, le rapport d'accélération est proportionnel au nombre de CPU.