Fermer

mars 23, 2023

Java Project Loom – Threads virtuels (Partie 1)

Java Project Loom – Threads virtuels (Partie 1)


Ce JEP No 425 est quelque chose que j’attends avec impatience. C’est une nouvelle notion qui vient s’ajouter au concurrent API de JDK 19. C’est en phase de prévisualisation, et bientôt ce sera une fonctionnalité permanente dans JDK dans les prochaines versions.

Les threads virtuels sont légers et réduisent l’effort d’écriture, de maintenance et d’observation des applications à haut débit.

Dans cette partie, nous verrons les objectifs de ce PEC.

Le premier consiste à permettre aux applications serveur écrites dans le style simple thread-per-request d’évoluer avec une utilisation matérielle quasi optimale.

Comprenons le « fil par demande » modèle. Eh bien, pour un serveur HTTP, cela signifie que chaque requête HTTP est gérée par son propre thread. Pour un serveur de base de données relationnelle, cela signifie que chaque transaction SQL est également gérée par son propre thread. Des trucs simples.

Une requête = une transaction = un thread.

Quel est le prix de ce modèle ? Eh bien, pour comprendre ce coût, nous devons comprendre le coût d’un thread en Java. Un thread Java, tel que créé dans les toutes premières versions de Java, est un mince wrapper sur un thread de plate-forme, également appelé Fil du système d’exploitation.

Maintenant, quelques trucs mathématiques en cours. Prenez une calculatrice à vos côtés.

Il y a deux choses que nous devons savoir à leur sujet. Tout d’abord, un thread de plate-forme doit stocker sa pile d’appels en mémoire. Pour cela, 20 Mo sont réservés à l’avance en mémoire. Deuxièmement, c’est une ressource système. Il faut environ 1 ms pour lancer un thread de plate-forme. Donc, 20Mo de mémoire, 1ms pour se lancer. Un thread de plate-forme est en fait une ressource assez coûteuse.

Comment pouvons-nous optimiser l’utilisation du matériel avec de tels threads ?

Supposons que nous ayons 16 GB de mémoire disponible pour votre application. Divisé par 20 Mo pour un fil, vous avez de la place pour 800 fils (16 * 1000/20) sur une telle machine. Supposons que ces threads effectuent des E/S, comme accéder à des ressources sur un réseau. Et supposons que cette ressource soit accessible dans 100 millisecondes. La préparation de la demande et le traitement de la réponse se feront de l’ordre de 500 nanosecondes chacun(comme vu ci-dessus.). Supposons que tous ces calculs en mémoire prennent 1000 nanosecondes. Maintenant à partir de la figure, puisque 1 milliseconde = 1000 000 nanosecondescela signifie qu’il existe un facteur de l’ordre de 100 000 entre la préparation de la demande et le traitement de la réponse. Pendant ce temps, notre fil est assis là, sans rien faire. Dépenser des milliers de dollars sur le processeur pour le rendre inactif. Quel dommage?

Donc si nous avons 800 ces threads, notre CPU sera utilisé à 0,8 %. Moins que 1%. Et si nous doublons la mémoire pour 32 Goil sera utilisé à 1,3 %. Si nous voulons une utilisation du processeur de 90 %, nous avons besoin de 90 000 threads de ce type. Leur lancement prendra 90s, soit 1 minute et demie, et ils consommeront 1,8 To de mémoire. Si une telle RAM est disponible sur le marché, je suis à peu près sûr que peu de gens peuvent se le permettre. Il est donc clair que les threads de plate-forme sont beaucoup trop coûteux à mettre à l’échelle avec une utilisation matérielle quasi optimale. Project Loom s’attaque à ce problème.

Le deuxième objectif est de permettre au code existant construit sur les threads Java classiques d’adopter les threads virtuels avec un minimum de modifications. Cet objectif est également assez ambitieux, car cela signifie que tout ce que vous pourriez faire avec les Threads classiques, vous devriez pouvoir le faire de la même manière avec les Threads virtuels. Cela couvre plusieurs points clés :

D’abordle thread virtuel peut exécuter n’importe quel code Java ou n’importe quel code natif.

Deuxièmevous n’avez pas besoin d’apprendre de nouveaux concepts.

Troisième, mais vous devez désapprendre certaines idées. Les threads virtuels sont bon marché, environ 1000 fois moins chers que les threads de plate-forme classiques, donc essayer d’éviter de bloquer un thread virtuel est inutile. L’écriture de code de blocage classique est OK. Et c’est une bonne nouvelle, car le code de blocage est tellement plus facile à écrire que le code asynchrone.

Est-ce une bonne idée de regrouper les threads virtuels ? La réponse est un grand non-non, car c’est bon marché, pas besoin de les regrouper, de les créer et de les lancer à la demande.

Deux autres bonnes nouvelles avec les threads virtuels Premièrement, fil local les variables fonctionnent également de la même manière. Et deuxieme, synchronisation fonctionne aussi. Maintenant, plusieurs choses doivent être dites à propos de la synchronisation. Un thread virtuel est toujours en cours d’exécution au-dessus d’un thread de plate-forme. Il y a encore un fil de plate-forme en dessous. L’astuce est que ce thread virtuel peut être détaché de son thread de plate-forme afin que ce thread de plate-forme puisse exécuter un autre thread virtuel. Quand serait-il détaché ? Eh bien, un thread virtuel peut être détaché de son thread de plate-forme dès qu’il bloque. Il peut être bloqué sur une opération d’E/S, ou sur un synchronisation fonctionnement, ou lorsqu’il est mis à dormir.

Une mise en garde, si un thread virtuel exécute du code à l’intérieur d’un synchronisé bloc, il ne peut pas être détaché de son fil de plate-forme. Ainsi, pendant le temps qu’il fonctionne, le synchronisé bloc de code, il bloque un thread de plate-forme. Si ce temps est court, ce n’est pas grave, il n’y a pas lieu de paniquer. Si ce temps est long, c’est-à-dire s’il effectue une longue opération d’E/S, alors ce n’est pas une bonne situation, nous devrons peut-être faire quelque chose. Nous devons remplacer synchronisé bloquer avec les API de verrouillage réentrant. Ce problème avec synchronisé blocs peuvent être résolus à l’avenir, en fait, ils peuvent être résolus au moment où les threads virtuels deviennent une fonctionnalité finale du JDK.

Programmation réactive est également disponible sur le marché et tente également de résoudre ce problème. Mais le problème avec le réactif est qu’il s’agit d’un changement de paradigme complet dans la façon dont nous codons. C’est difficile à apprendre, difficile à comprendre, difficile à profiler le code, encore plus difficile à déboguer, et un cauchemar pour écrire des cas de test.

J’espère que vous avez compris les problèmes que ce projet Loom essaie de résoudre. Dans les parties à venir, nous examinerons un peu de codage. Je suis enthousiasmé par ce projet. Faites-moi part de votre réaction en commentaires.

Ce blog est initialement publié dans Medium, lisez ici.

TROUVÉ CELA UTILE ? PARTAGEZ-LE




Source link