Comment puis-je choisir entre les différentes façons de faire du Threading en Delphi?
il semble que j'ai finalement dû mettre en place une sorte de threading dans mon programme Delphi 2009. S'il n'y avait qu'une façon de le faire, je m'enfuirais. Mais je vois plusieurs possibilités.
est-ce que quelqu'un peut expliquer quelle est la différence entre ceux-ci et pourquoi je choisirais l'un plutôt que l'autre.
-
La classe TThread en Delphi
-
... tout les autres?
modifier:
je viens de lire un excellent article de Gabr dans le numéro de mars 2010 (N ° 10) de Blaise Pascal Magazine intitulé "quatre façons de créer un fil". Vous devez vous abonner pour obtenir du contenu pour le magazine, donc par copyright, Je ne peux pas reproduire quoi que ce soit de substantiel à ce sujet ici.
En résumé, Gabr décrit la différence entre l'utilisation de TThreads, les appels directs de L'API Windows, les appels asynchrones D'Andy, et sa propre bibliothèque Omnithreadli. Il conclut à la fin que:
" Je ne dis pas que vous devez choisir autre chose que la manière Delphi classique (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 OmniThreadLibrary peut être préférable. Mais je suis toujours intéressé par les opinions de chacun sur la façon dont je (ou n'importe qui) devrait choisir leur méthode de filetage pour leur application.
et vous pouvez ajouter à la liste:
. 4. Appels directs vers L'API Windows
. 5. Misha Charrett CSI Application Distribuée Cadre comme suggéré par LachlanG dans sa réponse.
Conclusion:
je vais probablement choisir OmniThreadLibrary. J'aime Gabr. J'ai utilisé son profiler GPProfile il y a de nombreuses années, et j'utilise actuellement son GPStringHash qui fait en fait partie de OTL.
ma seule préoccupation pourrait être l'amélioration il à travailler avec 64 bits ou Unix / Mac une fois que Amarcadero ajoute cette fonctionnalité dans Delphi.
5 réponses
si vous n'avez pas d'expérience avec le multi-filetage , vous ne devriez probablement pas commencer par TThread
, car il s'agit d'une couche mince sur filetage natif. Je considère qu'il est également un peu rugueux sur les bords; il n'a pas beaucoup évolué depuis L'introduction avec Delphi 2, la plupart du temps des changements pour tenir compte de la compatibilité Linux dans le cadre de temps Kylix, et de corriger les défauts les plus évidents (comme la fixation de la classe de musculation cassée, et finalement déprécier Suspend()
et Resume()
dans le dernière version Delphi).
en utilisant une classe simple thread wrapper essentiellement aussi provoque le développeur de se concentrer sur un niveau qui est beaucoup trop faible. Pour utiliser correctement plusieurs cœurs de processeur, il est préférable de se concentrer sur les tâches plutôt que sur les threads, car le partitionnement du travail avec les threads ne s'adapte pas bien à l'évolution des exigences et des environnements - en fonction du matériel et des autres logiciels fonctionnant en parallèle, le nombre optimal de threads peut varier considérablement, même à différents niveaux. fois sur le même système. Une bibliothèque à laquelle vous passez seulement des morceaux de travail, et qui les planifie automatiquement pour faire le meilleur usage des ressources disponibles aide beaucoup à cet égard.
AsyncCalls est une bonne première étape pour introduire des threads dans une application. Si vous avez plusieurs domaines dans votre programme où un certain nombre d'étapes fastidieuses doivent être effectuées qui sont indépendants les uns des autres, alors vous pouvez simplement les exécuter asynchrones en passant chacun d'eux à AsyncCalls. Même si vous n'avez qu'une seule action qui prend du temps, vous pouvez l'exécuter de manière asynchrone et simplement afficher un UI de progression dans le thread VCL, en autorisant éventuellement l'annulation de l'action.
AsyncCalls est IMO pas si bon pour les travailleurs de fond qui restent autour pendant toute la durée du programme, et il peut être impossible d'utiliser lorsque certains des objets dans votre programme ont une affinité de fil (comme les connexions de base de données ou OLE objets qui peuvent avoir une exigence que tous les appels se passent dans le même fil).
ce que vous devez aussi savoir, c'est que ces actions asynchrones sont et non du genre" feu et oubli". Chaque fonction AsyncCall()
chargée renvoie un pointeur d'interface IAsyncCall
que vous pourriez avoir besoin de garder une référence si vous voulez éviter le blocage. Si vous ne conservez pas de référence, alors au moment où le nombre de références atteint zéro, l'interface sera libérée, ce qui causera la libération du thread. l'interface d'attendre l'appel asynchrone terminer. C'est quelque chose que vous pourriez voir pendant le débogage, en sortant de la méthode qui a créé le IAsyncCall
peut prendre une mystérieuse quantité de temps.
OTL est à mon avis la plus polyvalente de vos trois options, et je l'utiliserais sans autre réflexion. Il peut faire tout TThread
et Asyncalls peut faire, plus beaucoup plus. Il a une conception saine, qui est assez de haut niveau à la fois pour faire la vie pour l'utilisateur facile, et de laisser un port à un système Unixy (tout en gardant la plupart de l'interface intacte) regarder au moins possible, si ce n'est pas facile. Au cours des derniers mois, il a également commencé à acquérir des concepts de haut niveau pour le travail parallèle, fortement recommandé.
OTL a aussi quelques douzaines d'échantillons, ce qui est important pour commencer. Asyncalls n'a que quelques lignes dans les commentaires, mais il est alors assez facile à comprendre en raison de sa fonctionnalité limitée (il ne fait qu'une chose, mais il fait elle est bien). TThread
n'a qu'un seul exemple, qui n'a pas vraiment changé en 14 ans et est surtout un exemple de comment ne pas faire des choses.
quelle que soit l'option choisie, aucune bibliothèque n'éliminera le besoin de comprendre les bases du threading. Avoir lu un bon livre sur ceux-ci est une condition préalable à tout codage réussi. Un verrouillage approprié est par exemple une exigence pour tous.
il existe une autre bibliothèque de filetage Delphi moins connue, CSI Application Framework de Misha Charrett .
il est basé sur le passage de message plutôt que sur la mémoire partagée. Le même mécanisme de passage de message est utilisé pour communiquer entre des threads tournant dans le même processus ou dans d'autres processus, donc c'est à la fois une bibliothèque fileteuse et une bibliothèque de communication distribuée entre processus.
Il y a un peu d'apprentissage courbe pour commencer mais une fois que vous partez, vous n'avez pas à vous soucier de tous les problèmes de filetage traditionnels tels que les blocages et la synchronisation, le cadre prend soin de la plupart de cela pour vous.
Misha développe cela depuis des années et continue d'améliorer activement le cadre et la documentation Tout le temps. Il est toujours très réceptif aux questions de soutien.
TThread est une classe simple qui encapsule un fil de fenêtres. Vous créez une classe descendante avec une méthode D'exécution qui contient le code que ce thread doit exécuter, créez le thread et définissez-le à exécuter et le code s'exécute.
Asyncccalls et OmniThreadLibrary sont deux bibliothèques qui construisent un concept de plus haut niveau sur le dessus des threads. Il s'agit d'environ tâches , pièces discrètes de travail que vous devez avoir exécuter asynchrone. Vous commencez à la bibliothèque, elle met en place un pool de tâches, un groupe de threads spéciaux dont le travail est d'attendre jusqu'à ce que vous ayez du travail pour eux, et 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 il l'exécute dans l'un des threads de pool de tâches et gère beaucoup des détails de bas niveau pour vous.
je n'ai pas employé de bibliothèque, donc je ne peux pas vraiment vous donner une comparaison entre les deux. Essayer et de voir ce qu'ils peuvent faire, et dont on se sent le mieux pour vous.
(désolé, je n'ai pas assez de points pour commentaire, donc je suis en train de mettre cela dans une réponse plutôt qu'un autre vote pour OTL)
j'ai utilisé TThread, CSI et OmniThread (OTL). Les deux bibliothèques ont toutes deux des courbes d'apprentissage non triviales, mais sont beaucoup plus capables que TThread. Ma conclusion est que si vous allez faire quelque chose d'important avec threading vous finirez par écrire la moitié de la fonctionnalité de la bibliothèque de toute façon, donc vous pourriez aussi bien commencer par le travail, débogué la version de quelqu'un d'autre a écrit. Misha et Gabr sont de meilleurs programmeurs que la plupart d'entre nous, donc il y a des chances qu'ils aient fait un meilleur travail que nous.
j'ai regardé Asyncalls mais ça n'a pas fait assez de ce que je voulais. Une chose qu'il a est une fonction "Synchroniser" (absent de OTL) donc si vous êtes dépendant de ce que vous pourriez aller avec AynscCalls purement pour cela. IMO utilisant la transmission de messages n'est pas assez difficile à justifier la méchanceté de synchroniser, alors fléchissez la ceinture et apprenez comment pour utiliser des 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à la JCL ou si vous ne travaillez qu'à un seul endroit, mais je fais un mélange incluant le travail contractuel et la vente aux 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. Ça a l'air idiot, mais c'est important pour beaucoup de gens.
avec OTL la combinaison de la recherche des exemples et du code source pour les mots-clés, et de poser des questions dans les forums fonctionne pour moi. Je suis familier avec les tâches traditionnelles de threading "offload CPU-intensive tasks", mais en ce moment je travaille sur le backgroundounding 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 maxing out, mais en arrêtant un est généralement impossible.
je sais que ce n'est pas la méthode la plus avancée :-) et peut-être il a des limites aussi, mais je viens d'essayer le système. BeginThread et l'a trouvé assez simple-probablement en raison de la qualité de la documentation à laquelle je faisais référence... http://www.delphibasics.co.uk/RTL.asp?Name=BeginThread (IMO Neil Moffatt pourrait enseigner une chose ou deux au MSDN)
C'est le plus grand facteur que je trouve en essayant d'apprendre de nouvelles choses, le qualité de la documentation, pas quantité . Quelques heures ont suffi, puis j'ai repris le vrai travail au lieu de m'inquiéter de la façon d'obtenir le fil pour faire ses affaires.
EDIT en fait, Rob Kennedy fait un excellent travail en expliquant BeginThread ici BeginThread Structure-Delphi
MODIFIER en fait, la façon dont Rob Kennedy explique TThread dans le même post, je pense que je vais changer mon code pour utiliser TThread demain. Qui sait à quoi ressemblera la semaine prochaine! (Asyncalls maybe)