Performances de création de threads Java vs performances de création de threads C # vs C ++ (threads natifs)?

Je suis intéressant de savoir quels sont les coûts réels de la création de threads en Java, C # et C ++? Je sais que lorsque le thread est en train de créer un tas d’opérations doit être fait: allouer stack de thread, initialiser les descripteurs, etc.

Mais je suis intéressant dans les coûts réels. C # et Java utilisent différentes machines virtuelles et différents JIT et C ++ exécute du code natif. Le temps de création du fil est donc différent dans toutes ces langues. J’ai aussi entendu dire que la création de threads en Java est beaucoup plus lente qu’en C #. Quelqu’un peut-il donner des réponses et des explications autoritaires sur cette question?

C’est ce qui se produit lorsqu’un fil est créé.

Lorsqu’un nouveau thread est créé, il partage sa section de code, sa section de données et les ressources du système d’exploitation, comme des fichiers ouverts avec d’autres threads. Mais il se voit atsortingbuer sa propre stack, son jeu de registres et un compteur de programme.

Coûts de fil

Le threading a un coût réel pour votre programme (et le système) en termes d’utilisation et de performance de la mémoire. Chaque thread nécessite l’allocation de mémoire dans l’espace mémoire du kernel et dans l’espace mémoire de votre programme.

Les structures de base nécessaires pour gérer votre thread et coordonner sa planification sont stockées dans le kernel à l’aide de la mémoire câblée. L’espace de stack et les données par thread de votre thread sont stockés dans l’espace mémoire de votre programme.

La plupart de ces structures sont créées et initialisées lors de la création du thread, processus qui peut être relativement coûteux en raison des interactions requirejses avec le kernel.

Certains de ces coûts sont configurables, tels que la quantité d’espace de stack allouée aux threads secondaires. Le temps nécessaire à la création d’un thread est une approximation approximative et ne doit être utilisé que pour des comparaisons relatives les unes avec les autres. Les durées de création des threads peuvent varier considérablement en fonction de la charge du processeur, de la vitesse de l’ordinateur et de la quantité de mémoire système et programme disponible.

entrez la description de l'image ici

Les threads ne consumnt pas de mémoire (à part leur stack, de taille constante); les processus consumnt de la mémoire. L’intérêt des threads est qu’ils partagent l’état du processus.

L’ espace de stack des threads CLR ( Common Language Runtime ) est défini sur 1 Mo (4 Mo pour les threads de code 64 bits) (défini par le CLR) par défaut.

En C ++, il réserve 1 Mo pour la stack (il mappe son espace d’adressage), mais il n’est pas nécessairement alloué dans la mémoire physique, mais dans une partie plus petite de celle-ci. Si la stack augmente plus que cela, une erreur de page est générée et davantage de mémoire physique est allouée.

La création de threads Java est coûteuse car elle demande beaucoup de travail:

  • Un grand bloc de mémoire doit être alloué et initialisé pour la stack de threads.

  • Des appels système doivent être effectués pour créer / enregistrer le thread natif avec le système d’exploitation hôte.

  • Les descripteurs doivent être créés, initialisés et ajoutés aux structures de données internes de la machine virtuelle Java.

Il est également coûteux en ce sens que le fil relie des ressources tant qu’il est en vie; par exemple, la stack de threads, tous les objects pouvant être atteints à partir de la stack, les descripteurs de threads JVM, les descripteurs de threads natifs du système d’exploitation.

Analyse comparative de la création de 10 000 threads en C #, Java et Visual C ++:

C #

class Program { static void Main(ssortingng[] args) { Stopwatch watch = new Stopwatch(); watch.Start(); for (int i = 0; i < 10000; i++) { Thread thread = new Thread(DoNothing); thread.Start(); } watch.Stop(); Console.WriteLine(watch.Elapsed); } static void DoNothing() { //Do Nothing } } 

Résultat: 1.7638042 secondes

Java

 public class ThreadBencher { public static void main(Ssortingng[] args) { Runnable r = new Runnable() { public void run() { //Do nothing } }; long startTime = System.nanoTime(); for (int i = 0; i < 10000; i++) { Thread thread = new Thread(r); thread.start(); } long stopTime = System.nanoTime(); long totalTime = stopTime - startTime; System.out.print(totalTime); } } 

Résultat: 1,514557805 secondes (ou 1514557805 nanosecondes)

Visual C ++

 DWORD WINAPI DoNothing( LPVOID lpParam ) { return 0; } void main() { HANDLE ourThreadHandle = 0; SYSTEMTIME st1; SYSTEMTIME st2; int i; GetLocalTime(&st1); for (i = 0; i < 10000; i++) { ourThreadHandle = CreateThread( NULL, 0, DoNothing, 0, 0, NULL); } GetLocalTime(&st2); double dblSt1 = st1.wSecond + (st1.wMilliseconds / 1000); double dblSt2 = st2.wSecond + (st2.wMilliseconds / 1000); double result = dblSt2 - dblSt1; cout << st1.wSecond << "." << st1.wMilliseconds << endl; cout << st2.wSecond << "." << st2.wMilliseconds << endl; } 

Résultat (après calcul manuel de la sortie): 0,925 seconde

(Avertissement: je ne connais pas très bien le C ++, le code C ++ est donc assez patché ensemble)

Remarque: cette opération a été effectuée dans un environnement Windows 8 64 bits.

C ++ est généralement une langue plus rapide à exécuter, bien que cela puisse être une langue plus difficile à apprendre; donc plus de temps pour comprendre davantage de fonctions de base, ce qui peut ralentir le processus de codage lorsque vous effectuez l’application