Question

Maintenir l’interface graphique en attente pendant que l’application effectue un traitement exigeant en ressources CPU est l’un des défis de la programmation efficace en interface graphique.

Voici une bonne discussion sur la manière de procéder dans wxPython. Pour résumer, il y a 3 façons:

  1. Utiliser les discussions
  2. Utiliser wxYield
  3. Coupez le travail et faites-le dans le gestionnaire d'événements IDLE

Quelle méthode vous avez-vous trouvée être la plus efficace? Les techniques d’autres frameworks (comme Qt, GTK ou Windows API) sont également les bienvenues.

Était-ce utile?

La solution

Fils. C’est ce que je cherche toujours parce que vous pouvez le faire dans tous les cadres dont vous avez besoin.

Et une fois que vous êtes habitué au multi-threading et au traitement parallèle dans un seul langage / framework, vous maîtrisez tous les frameworks.

Autres conseils

Définitivement les discussions. Pourquoi? L'avenir est multi-core. Presque tous les nouveaux processeurs ont plus d'un cœur ou, s'ils en ont un, ils peuvent prendre en charge l'hyperthreading et donc prétendre en avoir plus d'un. Pour utiliser efficacement les processeurs multicœurs (et Intel envisage de passer à 32 cœurs dans un avenir proche), vous avez besoin de plusieurs threads. Si vous exécutez le tout dans un seul thread principal (généralement le thread de l'interface utilisateur est le thread principal), les utilisateurs disposeront de processeurs dotés de 8, 16 et un jour de 32 cœurs et votre application n'en utilisera jamais plus d'un. IOW s'exécute beaucoup, beaucoup plus lentement. que cela puisse fonctionner.

En réalité, si vous planifiez une application de nos jours, je partirais du design classique et penserais à une relation maître / esclave. Votre interface utilisateur est le maître, sa seule tâche est d'interagir avec l'utilisateur. Cela consiste à afficher des données à l'utilisateur et à recueillir les entrées de l'utilisateur. Chaque fois que votre application a besoin de "traiter des données", (même de petites quantités et de grandes quantités bien plus importantes), créez une "tâche". de toute nature, transmettez cette tâche à un thread d’arrière-plan et demandez au thread d’exécuter la tâche, en fournissant des informations à l’UI (par exemple, le pourcentage de tâches terminées ou le fait que la tâche soit toujours en cours ou non, afin que l’UI puisse afficher un " ; indicateur de travaux en cours "). Si possible, divisez la tâche en plusieurs petites sous-tâches indépendantes et exécutez plusieurs processus en arrière-plan, en attribuant une sous-tâche à chacun d'eux. De cette façon, votre application peut réellement tirer profit du multi-cœur et obtenir plus rapidement plus de processeurs ont de cœurs

En fait, des entreprises comme Apple et Microsoft envisagent déjà de créer plusieurs interfaces utilisateur multithread. Même avec l'approche ci-dessus, vous pouvez un jour penser que l'interface utilisateur est le goulet d'étranglement lui-même. Les processus en arrière-plan peuvent traiter des données beaucoup plus rapidement que l'interface utilisateur ne peut les présenter à l'utilisateur ou lui demander sa saisie. Aujourd'hui, de nombreux frameworks d'interface utilisateur sont peu thread-safe, beaucoup ne sont pas thread-safe du tout, mais cela va changer. Le traitement en série (une tâche après l'autre) est une conception en voie de disparition, le traitement en parallèle (plusieurs tâches à la fois) est la voie de l'avenir. Il suffit de regarder les adaptateurs graphiques. Même la carte NVidia la plus moderne présente des performances médiocres si vous regardez la vitesse de traitement en MHz / GHz du GPU seul. Comment se fait-il qu'il puisse vaincre la merde des processeurs en matière de calculs 3D? Simple: au lieu de calculer un point polygone ou un pixel de texture après l'autre, il en calcule plusieurs en parallèle (en fait tout un tas à la fois) et atteint ainsi un débit qui fait encore pleurer les processeurs. Par exemple. l'ATI X1900 (pour nommer le concurrent également) dispose de 48 unités de shader!

Je pense que delayresult est ce que vous recherchez:

http://www.wxpython.org/docs /api/wx.lib.delayedresult-module.html

Voir la démonstration de wxpython pour un exemple.

Fils ou processus en fonction de l'application. Parfois, il est préférable que l’interface graphique soit son propre programme et n’envoie que des appels asynchrones à d’autres programmes quand elle a du travail à faire. Vous aurez toujours plusieurs threads dans l'interface graphique pour surveiller les résultats, mais cela peut simplifier les choses si le travail effectué est complexe et n'est pas directement connecté à l'interface graphique.

Sujets - Utilisons une vue simple à deux couches (interface graphique, logique d'application).

Le travail de logique d'application doit être effectué dans un thread Python séparé. Pour les événements asynchrones devant être propagés jusqu'à la couche d'interface graphique, utilisez le système d'événements de wx pour publier des événements personnalisés. La publication d'événements wx est thread-safe, vous pouvez donc le faire dans plusieurs contextes.

Dans l’autre sens (événements d’entrée de l’interface graphique déclenchant la logique de l’application), j’ai trouvé qu’il était préférable de lancer un système d’événements personnalisé. Utilisez le module File d'attente pour disposer d'un moyen thread-safe d'insérer et de faire apparaître des objets d'événement. Ensuite, pour chaque fonction membre synchrone, associez-la à une version asynchrone qui pousse l'objet de fonction de synchronisation et les paramètres dans la file d'attente des événements.

Cela fonctionne particulièrement bien si une seule opération de niveau logique d'application peut être effectuée à la fois. L'avantage de ce modèle est que la synchronisation est simple: chaque fonction synchrone fonctionne dans son propre contexte de manière séquentielle du début à la fin, sans souci de préemption ou de rendement codé manuellement. Vous n'aurez pas besoin de verrous pour protéger vos sections critiques. À la fin de la fonction, publiez un événement sur la couche d'interface graphique indiquant que l'opération est terminée.

Vous pouvez redimensionner cette option pour autoriser plusieurs threads au niveau de l'application, mais les problèmes habituels liés à la synchronisation réapparaîtront.

edit - J'ai oublié la beauté de cette fonctionnalité, car il est possible de découpler complètement la logique d'application du code de l'interface graphique. La modularité est utile si vous décidez d'utiliser un autre cadre ou d'utiliser une version en ligne de commande de l'application. Pour ce faire, vous aurez besoin d’un répartiteur d’événements intermédiaire (niveau d’application - > interface graphique) implémenté par la couche d'interface graphique.

Utilisation de Qt / C ++ pour Win32.

Nous divisons les principales unités de travail en différents processus. L’interface graphique s’exécute en tant que processus distinct et permet de commander / recevoir des données du "travailleur" " processus au besoin. Fonctionne bien dans le monde multi-core d'aujourd'hui.

Cette réponse ne s'applique pas à la question du PO concernant Python, mais constitue plutôt une méta-réponse.

La méthode la plus simple consiste à utiliser les threads. Cependant, toutes les plates-formes ne disposent pas d'un threading préemptif (par exemple, BREW ou d'autres systèmes intégrés). Si possible, divisez simplement le travail et exécutez-le dans le gestionnaire d'événements IDLE.

Un autre problème lié à l'utilisation de threads dans BREW est qu'il ne nettoie pas les objets de pile C ++. Il est donc trop facile de perdre de la mémoire si vous tuez simplement le thread.

J'utilise des threads pour que la boucle d'événements principale de l'interface graphique ne soit jamais bloquée.

Pour certains types d'opérations, l'utilisation de processus distincts est très utile. De retour dans la journée, engendrer un processus entraînait beaucoup de frais généraux. Avec le matériel moderne, cette surcharge ne représente même pas un soubresaut sur l’écran. Cela est particulièrement vrai si vous créez un processus de longue durée.

Un avantage (discutable) est qu’il s’agit d’un modèle conceptuel plus simple que celui de threads pouvant conduire à un code plus facile à gérer. Cela peut également faciliter le test de votre code, car vous pouvez écrire des scripts de test qui exercent ces processus externes sans impliquer l'interface graphique. Certains pourraient même dire que c'est le principal avantage.

Dans le cas de certains codes sur lesquels j’avais travaillé une fois, le passage de threads à des processus séparés a entraîné une réduction nette de plus de 5000 lignes de code tout en rendant l’interface graphique plus réactive, en facilitant la maintenance et le test du code, tout en améliorant les performances globales.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top