63 votes

Comment choisir entre les différentes façons de faire du threading dans Delphi ?

Il semble que j'ai finalement réussi à mettre en œuvre une sorte de threading dans mon programme Delphi 2009. S'il n'y avait qu'une seule façon de le faire, je serais déjà prêt. Mais je vois plusieurs possibilités.

Quelqu'un peut-il m'expliquer quelle est la différence entre les deux et pourquoi je choisirais l'une plutôt que l'autre ?

  1. La classe TThread dans Delphi

  2. AsyncCalls par Andreas Hausladen

  3. OmniThreadLibrary par Primoz Gabrijelcic (gabr)

  4. ... d'autres ?


Edit :

Je viens de lire un excellent article de Gabr dans le numéro de mars 2010 (n° 10) de la revue Magazine Blaise Pascal intitulé "Quatre façons de créer un fil". Il faut s'abonner pour avoir accès au magazine, donc, en vertu des droits d'auteur, je ne peux pas reproduire ici quoi que ce soit de substantiel.

En résumé, Gabr décrit la différence entre l'utilisation de TThreads, les appels directs à l'API Windows, les AsyncCalls d'Andy et sa propre OmniThreadLibrary. Il conclut cependant à la fin que :

"Je ne dis pas que vous devez choisir autre chose que la méthode classique de Delphi (TThread) mais il est toujours bon d'être informé des options que vous avez"

La réponse de Mghie est très complète et suggère que OmniThreadLibrary est peut-être préférable. Mais je suis toujours intéressé par les opinions de chacun sur la façon dont je (ou quiconque) devrait choisir sa méthode de threading pour son application.

Et vous pouvez ajouter à la liste :

. 4. Appels directs à l'API Windows

. 5. Misha Charrett Cadre d'application distribué du CSI comme suggéré par LachlanG dans sa réponse.


Conclusion :

Je vais probablement opter pour OmniThreadLibrary. J'aime le travail de Gabr. J'ai utilisé son profileur GPProfile il y a plusieurs années, et j'utilise actuellement son GPStringHash qui fait partie de OTL.

Mon seul souci pourrait être de le mettre à niveau pour qu'il fonctionne avec des traitements 64 bits ou Unix/Mac, une fois qu'Embarcadero aura ajouté cette fonctionnalité dans Delphi.

43voto

mghie Points 25960

Si vous n'avez pas d'expérience en matière de multithreading, vous ne devriez probablement pas commencer par l'option TThread car il ne s'agit que d'une fine couche sur le filage naturel. Je le considère également comme un peu brut de décoffrage ; il n'a pas beaucoup évolué depuis son introduction avec Delphi 2, principalement des changements pour permettre la compatibilité avec Linux à l'époque de Kylix, et pour corriger les défauts les plus évidents (comme la correction de la classe MREW cassée, et enfin la dépréciation de la classe MREW). Suspend() y Resume() dans la dernière version de Delphi).

L'utilisation d'une simple classe d'enveloppes de fils fait également en sorte que le développeur se concentre sur un niveau beaucoup trop bas. Pour faire bon usage de plusieurs cœurs de processeur, il vaut mieux se concentrer sur les tâches plutôt que sur les threads, car le partitionnement du travail avec des threads ne s'adapte pas bien aux exigences et aux environnements changeants - selon le matériel et les autres logiciels fonctionnant en parallèle, le nombre optimal de threads peut varier considérablement, même à différents moments sur le même système. Une bibliothèque à laquelle vous ne passez que des morceaux de travail et qui les planifie automatiquement pour utiliser au mieux les ressources disponibles est très utile à cet égard.

AsyncCalls est une bonne première étape pour introduire les threads dans une application. Si vous avez plusieurs zones dans votre programme où un certain nombre d'étapes chronophages doivent être exécutées, indépendamment les unes des autres, vous pouvez simplement les exécuter de manière asynchrone en passant chacune d'entre elles à AsyncCalls. Même lorsque vous n'avez qu'une seule action qui prend du temps, vous pouvez l'exécuter de manière asynchrone et simplement afficher une interface utilisateur de progression dans le thread VCL, permettant éventuellement d'annuler l'action.

AsyncCalls n'est pas très bon pour les travailleurs d'arrière-plan qui restent en place pendant toute la durée d'exécution du programme, et il peut être impossible de l'utiliser lorsque certains des objets de votre programme ont une affinité avec les threads (comme les connexions de base de données ou les objets OLE qui peuvent avoir une exigence que tous les appels se produisent dans le même thread).

Ce dont vous devez également être conscient, c'est que ces actions asynchrones sont no du genre "tirer et oublier". Toute surcharge AsyncCall() renvoie un IAsyncCall pointeur d'interface auquel vous devrez peut-être conserver une référence si vous voulez éviter le blocage. Si vous ne conservez pas de référence, l'interface sera libérée dès que le nombre de références atteindra zéro, ce qui obligera le thread qui libère l'interface à attendre que l'appel asynchrone soit terminé. C'est quelque chose que vous pouvez voir pendant le débogage, lorsque vous sortez de la méthode qui a créé l'interface. IAsyncCall peut prendre un temps mystérieux.

OTL est à mon avis la plus polyvalente de vos trois options, et je l'utiliserais sans hésiter. Il peut tout faire TThread et AsyncCalls peuvent faire, et bien plus encore. Il a une conception saine, qui est suffisamment de haut niveau pour rendre la vie de l'utilisateur facile, et pour laisser un portage vers un système Unixy (tout en gardant la plupart de l'interface intacte) sembler au moins possible, sinon facile. Au cours des derniers mois, il a également commencé à acquérir quelques constructions de haut niveau pour le travail en parallèle, ce qui est fortement recommandé.

OTL dispose également de quelques dizaines d'échantillons, ce qui est important pour commencer. AsyncCalls n'a rien d'autre que quelques lignes de commentaires, mais il est assez facile à comprendre en raison de sa fonctionnalité limitée (il ne fait qu'une chose, mais il la fait bien). TThread n'a qu'un seul échantillon, qui n'a pas vraiment changé en 14 ans et qui est surtout un exemple de ce qu'il ne faut pas faire.

Quelle que soit l'option choisie, aucune bibliothèque n'éliminera la nécessité de comprendre les bases de l'enfilage. La lecture d'un bon livre à ce sujet est une condition préalable à tout codage réussi. Le verrouillage correct, par exemple, est une exigence de toutes les bibliothèques.

7voto

LachlanG Points 3205

Il existe une autre bibliothèque de threading Delphi moins connue, la bibliothèque de Misha Charrett, intitulée Cadre d'application du CSI .

Il est basé sur le passage de messages plutôt que sur la mémoire partagée. Le même mécanisme de passage de messages est utilisé pour communiquer entre les threads fonctionnant dans le même processus ou dans d'autres processus. Il s'agit donc à la fois d'une bibliothèque de threads et d'une bibliothèque de communication interprocessus distribuée.

Il y a un peu de courbe d'apprentissage pour commencer, mais une fois que vous avez commencé, vous n'avez pas à vous soucier de tous les problèmes traditionnels de threading tels que les blocages et la synchronisation, le framework s'en charge pour vous.

Misha développe ce système depuis des années et continue d'améliorer activement le cadre et la documentation en permanence. Il est toujours très réactif aux questions de support.

6voto

Mason Wheeler Points 52022

TThread est une classe simple qui encapsule un thread Windows. Vous créez une classe descendante avec une méthode Execute qui contient le code que ce thread doit exécuter, vous créez le thread et le mettez en exécution et le code s'exécute.

AsyncCalls et OmniThreadLibrary sont deux bibliothèques qui construisent un concept de plus haut niveau au-dessus des threads. Il s'agit de tâches des éléments de travail discrets qui doivent être exécutés de manière asynchrone. Vous lancez la bibliothèque, elle met en place un pool de tâches, un groupe de threads spéciaux dont le travail consiste à attendre que vous ayez du travail pour eux, puis vous passez à la bibliothèque un pointeur de fonction (ou un pointeur de méthode ou une méthode anonyme) contenant le code qui doit être exécuté, et elle l'exécute dans l'un des threads du pool de tâches et gère beaucoup de détails de bas niveau pour vous.

Je n'ai pas beaucoup utilisé l'une ou l'autre de ces bibliothèques, donc je ne peux pas vraiment vous donner une comparaison entre les deux. Essayez-les et voyez ce qu'elles peuvent faire, et laquelle vous semble la meilleure.

6voto

(désolé, je n'ai pas assez de points pour commenter donc je mets ceci comme une réponse plutôt qu'un autre vote pour OTL)

J'ai utilisé TThread, CSI et OmniThread (OTL). Ces deux bibliothèques ont des courbes d'apprentissage non triviales mais sont beaucoup plus performantes que TThread. Ma conclusion est que si vous voulez faire quelque chose d'important avec le threading, vous finirez par écrire la moitié de la fonctionnalité de la bibliothèque de toute façon, donc vous pourriez aussi bien commencer avec la version fonctionnelle et déboguée que quelqu'un d'autre a écrite. Misha et Gabr sont tous deux de meilleurs programmeurs que la plupart d'entre nous, il y a donc de fortes chances qu'ils aient fait un meilleur travail que nous.

J'ai regardé AsyncCalls mais il ne faisait pas assez ce que je voulais. Une chose qu'il a, c'est une fonction "Synchronize" (absente de OTL), donc si vous êtes dépendant de cela, vous pourriez aller avec AynscCalls uniquement pour cela. L'utilisation du passage de messages n'est pas assez difficile pour justifier la méchanceté de Synchronize, alors attachez-vous et apprenez à utiliser les messages.

Des trois, je préfère OTL, en grande partie à cause de la collection d'exemples, mais aussi parce qu'il est plus autonome. C'est moins un problème si vous utilisez déjà le JCL ou si vous ne travaillez qu'à un seul endroit, mais je fais un mélange incluant du travail sous contrat et la vente de clients sur l'installation du système de Misha est plus difficile que l'OTL, juste parce que l'OTL est ~20 fichiers dans un répertoire. Cela semble idiot, mais c'est important pour de nombreuses personnes.

Avec OTL, la combinaison de la recherche de mots-clés dans les exemples et le code source et de la pose de questions dans les forums fonctionne pour moi. Je suis familier avec les tâches traditionnelles de threading "décharger les tâches intensives du CPU", mais en ce moment je travaille sur la mise en arrière-plan d'un tas de travail de base de données qui a beaucoup plus de "threads block waiting for DB" et moins de "CPU maxed out", et l'OTL fonctionne assez bien pour cela. Les principales différences sont que je peux avoir plus de 30 threads en cours d'exécution sans que le CPU ne soit au maximum, mais qu'il est généralement impossible d'en arrêter un.

2voto

Darian Miller Points 4915

Il y a une classe wrapper pour TThread sur Stack Overflow.

Question connexe de stack overflow

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