57 votes

Quelle est la charge de travail lors de la création d'un fil ?

Je viens de revoir un code vraiment terrible - un code qui envoie des messages sur un port série en créant un nouveau thread pour emballer et assembler le message dans un nouveau thread pour chaque message envoyé. Oui, pour chaque message, un pthread est créé, les bits sont correctement configurés, puis le thread se termine. Je n'ai aucune idée de la raison pour laquelle quelqu'un ferait une telle chose, mais cela soulève la question suivante : quelle est la surcharge lors de la création d'un thread ?

0 votes

Un seul fil de travail permettra de résoudre certains des autres types de conflits de ressources que vous pourriez avoir avec plusieurs fils (écritures entrelacées, etc.).

0 votes

Je voudrais dire que oui, c'est une chose horrible à faire - ce qui m'amène à ma question, combien de frais généraux sont encourus lors de la création d'un fil (en général) Franchement, je ne sais pas comment déterminer ou même mesurer une implémentation de la bibliothèque pthread.

13 votes

Les frais généraux sont 0.37% si le message est de la bonne taille.

7voto

J'ai utilisé le design "terrible" ci-dessus dans une application VOIP que j'ai réalisée. Cela a très bien fonctionné ... absolument aucune latence ou paquets manqués/abandonnés pour les ordinateurs connectés localement. Chaque fois qu'un paquet de données arrivait, un thread était créé et transmettait ces données pour les traiter vers les périphériques de sortie. Bien entendu, les paquets étaient volumineux, ce qui ne provoquait aucun goulot d'étranglement. Pendant ce temps, le thread principal pouvait revenir en boucle pour attendre et recevoir un autre paquet entrant.

J'ai essayé d'autres modèles où les fils dont j'ai besoin sont créés à l'avance, mais cela crée ses propres problèmes. Tout d'abord, vous devez concevoir votre code correctement pour que les threads puissent récupérer les paquets entrants et les traiter de manière déterministe. Si vous utilisez plusieurs threads (pré-alloués), il est possible que les paquets soient traités "dans le désordre". Si vous utilisez un seul thread (pré-alloué) pour boucler et récupérer les paquets entrants, il est possible que ce thread rencontre un problème et se termine, ne laissant aucun thread pour traiter les données.

La création d'un thread pour traiter chaque paquet de données entrant fonctionne très proprement, notamment sur les systèmes multicœurs et lorsque les paquets entrants sont volumineux. Pour répondre plus directement à votre question, l'alternative à la création de threads est de créer un processus d'exécution qui gère les threads pré-alloués. La possibilité de synchroniser le transfert et le traitement des données ainsi que la détection des erreurs peut ajouter autant, sinon plus, de frais généraux que la simple création d'un nouveau thread. Tout dépend de votre conception et de vos exigences.

6voto

2e0byo Points 143

La création de threads et le calcul dans un thread sont assez coûteux. Toutes les structures de données doivent être mises en place, le thread doit être enregistré auprès du noyau et un changement de thread doit se produire pour que le nouveau thread soit effectivement exécuté (dans un temps non spécifié et imprévisible). L'exécution de thread.start ne signifie pas que la fonction principale du thread est appelée immédiatement. Comme le souligne l'article (mentionné par typoking), la création d'un thread n'est bon marché que par rapport à la création d'un processus. Globalement, elle est assez coûteuse.

Je n'utiliserais jamais un fil

  • pour un court calcul
  • un calcul où j'ai besoin du résultat dans mon flux de code (que c'est-à-dire que je démarre le fil et j'attends qu'il renvoie le résultat de son calcul

Dans votre exemple, il serait logique (comme cela a déjà été souligné) de créer un thread qui gère toute la communication série et qui est éternel.

hth

Mario

6voto

Lunar Mushrooms Points 1412

À titre de comparaison, jetez un coup d'œil à OSX : Lien

  • Structures de données du noyau : Environ 1 Ko Espace pile : 512 Ko (threads secondaires) : 8 MB (thread principal OS X) , 1 MB (thread principal iOS) principal d'iOS)

  • Temps de création : Environ 90 microsecondes

La création du fil posix devrait également se situer autour de ce chiffre (pas très éloigné) je suppose.

3voto

R.. Points 93718

Dans toute implémentation sensée, le coût de la création d'un thread devrait être proportionnel au nombre d'appels système qu'il implique, et du même ordre de grandeur que les appels système familiers comme open y read . Quelques mesures occasionnelles sur mon système ont montré pthread_create prenant environ deux fois plus de temps que open("/dev/null", O_RDWR) Ce qui est très coûteux par rapport au calcul pur, mais très bon marché par rapport à toute opération d'entrée/sortie ou autre qui impliquerait de passer de l'espace utilisateur à l'espace noyau.

3voto

sosssego Points 31

C'est en effet très dépendant du système, j'ai testé le code de @Nafnlaus :

#include <thread>

int main(int argc, char** argv)
{
  for (volatile int i = 0; i < 500000; i++)
    std::thread([](){}).detach();
  return 0;
}

Sur mon ordinateur de bureau Ryzen 5 2600 :

Windows 10, compilé avec la version MSVC 2019 en ajoutant des appels std::chrono autour de lui pour le chronométrer. Au repos (uniquement Firefox avec 217 onglets) :

Cela a pris environ 20 secondes (20.274, 19.910, 20.608) (également ~20 secondes avec Firefox fermé)

Ubuntu 18.04 compilé avec :

g++ main.cpp -std=c++11 -lpthread -O3 -o thread

chronométré avec :

time ./thread

Il a fallu environ 5 secondes (5.595, 5.230, 5.297)

Le même code sur mon raspberry pi 3B compilé avec :

g++ main.cpp -std=c++11 -lpthread -O3 -o thread

chronométré avec :

time ./thread

a pris environ 15 secondes (16.225, 14.689, 16.235)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X