IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Tkinter Python Discussion :

mulitprocessing pool et tkinter


Sujet :

Tkinter Python

  1. #1
    Futur Membre du Club
    Inscrit en
    Août 2009
    Messages
    6
    Détails du profil
    Informations forums :
    Inscription : Août 2009
    Messages : 6
    Points : 5
    Points
    5
    Par défaut mulitprocessing pool et tkinter
    Bonjour à toutes et tous,

    Je suis sous debian 11, stable et j’utilise python 3.9

    J’ai un script python qui fonctionne bien quand il est lancé seul, en gros je produis des cartes météo avec matplotlib et des fichiers grib2 des modèles de météo-france.

    Mon script "standalone", on retrouve une classe qui contient une méthode une utilisant un pool de workers (multiprocessing) qui permet de parallèliser le dessin des cartes.
    En gros plusieurs cartes sont produites en parallèle (simultanément et sans attendre qu’une carte soit finie au lieu de séquentiellement), aucun problème, les données traitées sont indépendantes entres elles et j’ai 6 cœurs (12threads) sur mon core i5, autant en profiter

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    import matplotlib
    import pygrib
    import numpy as np
    import time
    from datetime import datetime
    from datetime import timedelta
    import matplotlib.pyplot as plt
    import cartopy.crs as ccrs
    import cartopy.feature as cfeature
    import cartopy.io.shapereader as shpreader
    import matplotlib.dates as mdates
    import matplotlib.colors as mcolors
    import metpy.plots as metplots
    from matplotlib.figure import Figure
    from multiprocessing import Pool
     
     
    class Arome_001_Cartes():
     
        def __init__(self,jour,mois,annee,run,zoom,verification):
     
        []
     
        def cartes_T2m(self):
            """Renvoie les cartes de températures à deux mètre prévues par Arome 0.025° ou 0.01°.
            Crée une figure par échéance donc une par heure, renvoie et sauvegarde l'intégralité des cartes."""
            self.type_de_carte = "T2m"
            self.construire_Noms()
            print(self.nom_fichier_1)
            print(self.nom_fichier_2)
     
            t_fichiers = ("00H","02H","03H","04H","05H","06H","07H","08H","09H","10H","11H","12H","13H","14H","15H",
                            "16H","17H","18H","19H","20H","21H","22H","23H","24H","25H","26H","27H","28H","29H","30H",
                            "31H","32H","33H","34H","35H","36H",)
     
            with Pool(6) as p:
                print(p.map(self.par_fichier_T2m, t_fichiers))
     
     
    h=Arome_001_Cartes("03","10","2021","06",zoom = 0,verification = 0)
    h.cartes_T2m()
    La compilation en parallèle se passe nickel, j’ai un gain de temps de facteur correspondant au nombre de cœurs (et donc de workers) utilisés \o/

    Maintentant j’essaye d’implémenter cette production de cartes dans une interface graphique.
    Je précise que je veux juste créer les cartes avec matplotib/cartopy et les enregistrer, les cartes produites ne sont pas affichées dans un canevas ou autre.
    Je veux appuyer sur un bouton et lancer la production de ces cartes, rien de graphique dans la gui, rien d’autre.

    Rapidement, voici une version simplifiée de ma gui avec tkinter:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    from multiprocessing import Pool
    import matplotlib
    matplotlib.use("TkAgg")
    import pygrib
    import numpy as np
    import time
    from datetime import datetime
    from datetime import timedelta
    import matplotlib.pyplot as plt
    import cartopy.crs as ccrs
    import cartopy.feature as cfeature
    import matplotlib.dates as mdates
    import matplotlib.colors as mcolors
    import metpy.plots as metplots
    from matplotlib.backends.backend_tkagg import FigureCanvasTk, NavigationToolbar2Tk
    from matplotlib.figure import Figure
    from tkinter import *
     
    from v0_6_Arome_Cartes import *
     
    # Classe d'interface graphique, les objets de cette classe sont appelées dans le main du projet.
    class Application(Tk): # Héritière de Tk, cette classe code pour une interface graphique.
     
        def __init__(self):
     
            Tk.__init__(self)        # constructeur de la classe parente
     
            # Pour Arome 0.025°
            # Boutons pour le tracé et l'enregistrement de toutes les cartes de toutes les échéances
            B_tout_3 = Button(self, text ="Dessiner toutes les cartes 3", command =self.dessiner_tout_aro_0025_T2m).pack()
     
        def dessiner_tout_aro_0025_T2m(self):    
            mod = "aro"
            res = "0.025"
            self.tout_aro_0025 = Arome_Cartes(self.date_du_run,modele=mod,resolution=res,zoom = self.chk,verification = 0)
            self.tout_aro_0025.cartes_T2m()
    Le code de la classe fille est quasiment indentique à sa version standalone:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    import matplotlib
    import pygrib
    import numpy as np
    import time
    from datetime import datetime
    from datetime import timedelta
    import matplotlib.pyplot as plt
    import cartopy.crs as ccrs
    import cartopy.feature as cfeature
    import cartopy.io.shapereader as shpreader
    import matplotlib.dates as mdates
    import matplotlib.colors as mcolors
    import metpy.plots as metplots
    from matplotlib.figure import Figure
    from multiprocessing import Pool
     
    class Arome_Cartes():
     
        def __init__(self,date_du_run,modele,resolution,zoom,verification):
     
        []
     
        def cartes_T2m(self):
     
            self.type_de_carte = "T2m"
            t_fichiers = self.construire_t_fichiers()
     
            with Pool(1) as p:
                print(p.map(self.par_fichier_T2m, t_fichiers))
    Avec un pool identique de plus de 1 workers, j’ai un freeze complet de ma machine, seule la souris bouge mais le reste est figé, obligation de hard reboot…
    Avec un seul worker, ça compile et les figures sont bien produites, mais j’ai une erreur à la fin:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    [xcb] Unknown sequence number while processing queue
    [xcb] Most likely this is a multi-threaded client and XInitThreads has not been called
    [xcb] Aborting, sorry about that.
    python3: ../../src/xcb_io.c:269: poll_for_event: Assertion `!xcb_xlib_threads_sequence_lost' failed.
    Abandon
    En me renseignant sur le web, je crois avoir compris que le thead qui exécute la boucle de la gui tkinter est le même qui se charge de lancer la méthode de production des cartes, donc si un thread doit se transformer en n-threads, ça coince…

    D’où ma question, est-il possible de résoudre mon problème, d’éviter que mes workers ne cassent le thread de la boucle tkinter ?

    Je me trompe peut-être mais je veux utiliser un pool de threads qui ne s’attendent pas pour se lancer, or il es fait mention d’une processing queue, donc on aurait plusieurs workers à la queue pour un seul thread.
    Cela équivaut à un retour au séquentiel non ?

    En l’état je me dis que je vais passer par subprocess.call pour lancer cette production, mais alors aurais-je la même erreur si le subprocess.call est lancé par un bouton de ma gui tkinter ?

    Bonne journée à toutes et tous et au plaisir de lire vos réponses

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 292
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 292
    Points : 36 788
    Points
    36 788
    Par défaut
    Salut,

    La règle est d'avoir le GUI qui tourne dans le thread principal... et le reste dans d'autres thread (ou process).
    Et pour communiquer, les échanges se font via des Queue.

    - W

  3. #3
    Futur Membre du Club
    Inscrit en
    Août 2009
    Messages
    6
    Détails du profil
    Informations forums :
    Inscription : Août 2009
    Messages : 6
    Points : 5
    Points
    5
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    Salut,

    La règle est d'avoir le GUI qui tourne dans le thread principal... et le reste dans d'autres thread (ou process).
    Et pour communiquer, les échanges se font via des Queue.

    - W
    Bonjour,

    Je précise que j’ai passé des heures sur mon problème et j’ai bien pris le temps de regarder la documentation disponible sur le web avant de revenir vers vous.

    Ce que j’ai pu trouver en ligne ne correspond pas à mon cas de figure donc je me dis que je dois mal comprendre quelque part.

    J’ai l’impression de me noyer dans un verre d’eau là…

    J’essaye particulièrement d’utiliser https://docs.python.org/fr/3/library...rocessing.html

    Dites moi si je me trompe, mais par défaut, la GUI est le thread principal, donc pas de souci dans mon cas.

    Je n’attends pas d’I/O donc je passe par du multiprocessing et pool est de loin le plus rapide que j’ai pu tester dans mon programme.

    Maintenant je sèche sur la manière de faire pour faire cette fameuse queue…

    Je suis bloqué quand j’essaye de mettre une queue pour les lignes 12 et 13
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class Arome_Cartes():
     
        def __init__(self,date_du_run,modele,resolution,zoom,verification):
     
        []
     
        def cartes_T2m(self):
     
            self.type_de_carte = "T2m"
            t_fichiers = self.construire_t_fichiers()
     
            with Pool(1) as p:
                print(p.map(self.par_fichier_T2m, t_fichiers))
    Je n’ai pas trouvé d’exemple dans la doc et sur les divers forums qui utilise un pool et une queue. Nul part, et j’ai cherché, la documentation n’est vraiment pas facile d’accès, si elle existe…

    Passer par multiprocessing.process et une queue semble forcéé en mode séquentiel, certainement par le GIL.

    Par exemple, quand je remplace les deux lignes du pool par quelque chose comme (j’ai fait BEAUCOUP d’essais qui donnent tous le même résultat "séquentiel"), les tâches sont exécutées séquentiellement:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    for t_fi in t_fichiers:
                q= Queue()
                q.put(self.par_fichier_T2m(t_fi))
                Process(q)
                Process.start()
    Faut-il donc que j’abandonne cette idée de classe utilisant une méthode qui a un pool de workers ?

    Faut-il donc que je modifie ma classe GUI pour créer une liste, lancer la méthode dans une queue, dans l’esprit de ceci ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    from v0_6_Arome_Cartes import *
     
    # Classe d'interface graphique, les objets de cette classe sont appelées dans le main du projet.
    class Application(Tk): # Héritière de Tk, cette classe code pour une interface graphique.
     
        def __init__(self):
     
            Tk.__init__(self)        # constructeur de la classe parente
     
            self.queue =  queue.Queue()
            # Pour Arome 0.025°
            # Boutons pour le tracé et l'enregistrement de toutes les cartes de toutes les échéances
            B_tout_3 = Button(self, text ="Dessiner toutes les cartes 3", command =self.dessiner_tout_aro_0025_T2m).pack()
     
        def dessiner_tout_aro_0025_T2m(self):    
            mod = "aro"
            res = "0.025"
            self.tout_aro_0025 = Arome_Cartes(self.date_du_run,modele=mod,resolution=res,zoom = self.chk,verification = 0)
            self.queue.put(self.tout_aro_0025.cartes_T2m())
    Il y a certainement un truc que je ne pige pas qui doit sauter aux yeux, mais je suis perdu là et c’est pas faute de recherches et d’essais…
    Au plaisir de vous lire, donc
    Bonne soirée/journée,
    L.

  4. #4
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 292
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 292
    Points : 36 788
    Points
    36 788
    Par défaut
    Salut,

    Plutôt que de vouloir déjà coder çà dans votre application, commencez par écrire un petit exemple plus simple. Si ça ne marche pas, ça vous permettrait de poster un code qu'on pourra faire fonctionner.
    De plus vous pouvez partir de l'exemple donné dans la documentation et l'adapter à vos besoins.
    Pour simplifier, vous pouvez aussi commencer par une mouture qui n'utilise pas tkinter.


    - W

  5. #5
    Futur Membre du Club
    Inscrit en
    Août 2009
    Messages
    6
    Détails du profil
    Informations forums :
    Inscription : Août 2009
    Messages : 6
    Points : 5
    Points
    5
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    Salut,

    Plutôt que de vouloir déjà coder çà dans votre application, commencez par écrire un petit exemple plus simple. Si ça ne marche pas, ça vous permettrait de poster un code qu'on pourra faire fonctionner.
    De plus vous pouvez partir de l'exemple donné dans la documentation et l'adapter à vos besoins.
    Pour simplifier, vous pouvez aussi commencer par une mouture qui n'utilise pas tkinter.


    - W
    Merci pour votre réponse, je suis en train de faire des essais avec une version très simple de mon code, je reviens demain ou samedi quand j’aurais digéré ces infos et que j’aurai les idées plus claire sur la question
    Bonne soirée,
    L.

Discussions similaires

  1. [TOMCAT] pool de connexion postgres
    Par kitov dans le forum Tomcat et TomEE
    Réponses: 4
    Dernier message: 04/06/2004, 16h13
  2. [WSAD] [POOL de CONNEXION]
    Par gandia dans le forum Eclipse Java
    Réponses: 2
    Dernier message: 19/05/2004, 18h22
  3. [débutant][tomcat][jdbc] pool de connection DBCP
    Par zozolh2 dans le forum JDBC
    Réponses: 6
    Dernier message: 19/05/2004, 17h41
  4. [EJB]JBoss et Pool de connexion
    Par Kleb dans le forum Wildfly/JBoss
    Réponses: 4
    Dernier message: 20/04/2004, 12h12
  5. [tomcat 4.1] [oracle] Pool de connexion
    Par Franco dans le forum Tomcat et TomEE
    Réponses: 6
    Dernier message: 23/09/2003, 00h42

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo