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

Python Discussion :

multiprocessing dans une def!


Sujet :

Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2017
    Messages
    22
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2017
    Messages : 22
    Par défaut multiprocessing dans une def!
    Bonjours, le script suivant fonctionne presque normalement lorsqu'il est dans un objet mais alors à partir du moment que je l'ai mis dans une définition, les choses se sont compliquées!
    Au début, les deux premiers passages se passaient à merveille mais dès la création du troisième objet, le calcul s’arrêtait en plein milieu, il se mettait en pause et les processeurs n'avait plus rien à se mettre sous la dent! (Je ne comprend pas pourquoi d’ailleurs!). Pour tenter d'y remédier, j'ai tout mis dans une définitions de façon à vraiment repartir à 0 à chaque fois que je la rappelle. Seulement, au lieu de faire une pause au troisième passage, Python exprime directement son mécontentement à travers le message suivant:

    File "fractale_objet.py", line 2707, in calculage_rapide
    matrice.extend([resultat.get() for resultat in liste_res])#Récupération des lignes qui viennent d'être calculées
    File "fractale_objet.py", line 2707, in <listcomp>
    matrice.extend([resultat.get() for resultat in liste_res])#Récupération des lignes qui viennent d'être calculées
    File "/usr/lib/python3.4/multiprocessing/pool.py", line 599, in get
    raise self._value
    File "/usr/lib/python3.4/multiprocessing/pool.py", line 383, in _handle_tasks
    put(task)
    File "/usr/lib/python3.4/multiprocessing/connection.py", line 206, in send
    self._send_bytes(ForkingPickler.dumps(obj))
    File "/usr/lib/python3.4/multiprocessing/reduction.py", line 50, in dumps
    cls(buf, protocol).dump(obj)
    _pickle.PicklingError: Can't pickle <function fractale.<locals>.calculage_rapide.<locals>.calcul at 0x7ff331942a60>: attribute lookup calcul on __main__ failed

    Bon, voila, je ne comprend pas vraiment le message mais il se trouve que là, il semble vraiment furax!

    Voici le code qui le met dans cet état:
    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
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
     
    def calculage_rapide(identifiant, lecture):
    	"""
            Rempli peu a peu la variable 'matrice'
            iters_max = nbr maximum d'itérations
            mod_carre = module maximum du nbr complex
            largeur = largeur de la matrice
            hauteur = hauteur de la marice
            z0 = premier terme de la suite
            suite = formule de récurence de la suite
            couleur = information que l'on enregistre dans la matrice
            xmin, xmax, ymin et ymax = dimension du plan complex
            iteration = True quand les itérations comptent et pas seulement le module
            nbr_couleur = Nombre totale de couleur différentes que peut avoir la fractale
            """
    	def calcul(ligne, hauteur):
    		"""
                    Remplissage d'une partie de la matrice
                    Retourne la ligne dans une liste
                    """
    		print("	Ligne n°"+str(ligne+1)+"----"+str(int(100*ligne/hauteur))+"%")
    		liste = []								#On initialise la liste que l'on va remplir
    		I = complex(0,1)							#Ainsi, I est considéré comme une variable
    		y = (ymax-ymin)*ligne/(hauteur-1)+ymin					#La partie imaginaire du plan complex
    		for colone in range(0,largeur):						#Pour chaque case de chaque ligne
    			x = (xmax-xmin)*colone/(largeur-1)+xmin				#La partie réel du plan complex
    			z = eval(z0)							#Création du premier rang de la suite
    			c = 0								#Initialisation du compteur
    			while (c<iters_max) and (((z.real**2)+(z.imag**2))<mod_carre):	#Tant qu'il n'y a aucune raison d'arrêter le calcul de la suite
    				c+=1							#Incrémentation du compteur
    				z = eval(suite)						#Calcul du rang suivant
    			if iteration:							#Si la divergence de la suite compte
    				c = c/iters_max						#On prend en compte le nombre d'itérations
    			else:								#Si le module de la suite compte
    				c = abs(z)/math.sqrt(mod_carre)				#Sinon, c'est le module de z qui est pris en compte
    			liste.append(int(c*nbr_couleurs)/nbr_couleurs)			#Ce pxl est ajouté à la ligne
    		return liste								#La ligne est la valeur de retour
     
    	global matrice,fin								#On fait en sorte que la matrice soit accessible dans tous le programme
     
    	if __name__ == "__main__":							#Si le programme en cours d’exécution est le programme principal
    		tuple1, tuple2 = lecture.lire_tout(identifiant)				#On récupère les données qui permettent de créer l'image
    		iters_max = tuple1[5]
    		mod_carre = tuple1[6]
    		largeur = tuple2[6]
    		hauteur = tuple2[7]
    		z0 = str(tuple1[7])
    		suite = str(tuple1[8])
    		xmin = tuple1[9]
    		xmax = tuple1[10]
    		ymin = tuple1[11]
    		ymax = tuple1[12]
    		iteration = tuple1[13]
    		nbr_couleurs = tuple1[4]
     
    		import multiprocessing							#On importe le module
    		pool = multiprocessing.Pool()						#Il est possible de mettre en argument: processes=nbr_de_coeurs
     
    		liste_res = []								#Tous les résultats seront enregistrés ici
    		compteur = 0								#On met le compteur à 0
    		for ligne in range(0,hauteur):						#Pour chacune des lignes à traiter
    			if fin: return None						#Si il faut en finir, on s'arrète de suite
    			compteur += 1							#On incrémente le compteur
    			liste_res.append(pool.apply_async(calcul, args=(ligne, hauteur)))#On s'en charge
    			compteur = compteur%(hauteur//10)				#C'est le nombre de boucles pandant lesquelles la matrice n'est pas actualisée
    			if compteur == 0:						#Si on en est à la 16ème boucle
    				pool.close()						#On arrète momentanément de charger la liste d'attente
    				pool.join()						#On lance les calculs en liste d'attente
    				matrice.extend([resultat.get() for resultat in liste_res])#Récupération des lignes qui viennent d'être calculées
    				pool = multiprocessing.Pool()				#On réinitialise le pooleur
    				liste_res = []						#On vide la liste des lignes qui ont déjà étés calculées
    		pool.close()								#Validation des dernières lignes
    		pool.join()								#Lancement des derniers calculs
    		matrice.extend([resultat.get() for resultat in liste_res])		#Récupération des derniers résultats
    		fin = True
    		print("		Fin du calcul")
    		return None
    En plus, ce qui complique le programme, c'est qu'il est impératif que la 'matrice' ait une portée global car un thread qui tourne en parallèle, se charge d'enregistrer chaque ligne sur le disque et de supprimer chaque ligne calculée affin de faire de la place en mémoire et de ne pas perdre de temps a la fin du calcul pour enregistrer l'image sur le disque.

    Encore une fois, je suis preneur de toutes les pistes qui permettraient de corriger ce plantage, ou bien d'une autre idée de conception qui aurait le même effet final.

  2. #2
    Expert confirmé

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 307
    Par défaut
    Salut,

    Il y a trop d'indentations incohérentes dans ton code. On y comprend que dalle.

  3. #3
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2017
    Messages
    22
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2017
    Messages : 22
    Par défaut
    Les indentations sont bien voulus. La def dans la def est la exprès. C'était au départ une méthode de l'objet. Je peux encore simplifier le code en enlevant le if 1 et le Else; qui sont en réalités des Try except au cas ou il ait un problème.

  4. #4
    Expert confirmé

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 307
    Par défaut
    Ben j'ai copié tel quel ton code dans un fichier texte et il est illisible.

  5. #5
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 752
    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 752
    Par défaut
    Salut,

    Le message d'erreur _pickle.PicklingError: Can't pickle <function fractale.<locals>.calculage_rapide.<locals>.calcul at 0x7ff331942a60>: attribute lookup calcul on __main__ failed dit en gros qu'il ne trouve pas de variable globale "calcul" dans le module '__main__'.
    Erreur que l'on peut reproduire avec bien moins de lignes:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    from multiprocessing import Pool
     
    def foo():
        def bar(x, y):
            pass
     
        pool = Pool()
        f = pool.apply_async(bar, args=(1, 2))
        f.wait()
        print (f.get())
     
    if __name__ == '__main__':
        foo()
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  6. #6
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2017
    Messages
    22
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2017
    Messages : 22
    Par défaut
    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
     
    def calculage_rapide(identifiant, lecture):
     
    	def calcul(ligne, hauteur):
    		liste = range(hauteur)
    		return liste
     
    	global matrice,fin								#On fait en sorte que la matrice soit accessible dans tous le programme
     
    	if __name__ == "__main__":							#Si le programme en cours d’exécution est le programme principal
    		import multiprocessing							#On importe le module
    		pool = multiprocessing.Pool()						#Il est possible de mettre en argument: processes=nbr_de_coeurs
    		liste_res = []								#Tous les résultats seront enregistrés ici
    		compteur = 0								#On met le compteur à 0
    		for ligne in range(0,hauteur):						#Pour chacune des lignes à traiter
    			if fin: return None						#Si il faut en finir, on s'arrète de suite
    			compteur += 1							#On incrémente le compteur
    			liste_res.append(pool.apply_async(calcul, args=(ligne, hauteur)))#On s'en charge
    			compteur = compteur%(hauteur//10)				#C'est le nombre de boucles pandant lesquelles la matrice n'est pas actualisée
    			if compteur == 0:						#Si on en est à la 16ème boucle
    				pool.close()						#On arrète momentanément de charger la liste d'attente
    				pool.join()						#On lance les calculs en liste d'attente
    				matrice.extend([resultat.get() for resultat in liste_res])#Récupération des lignes qui viennent d'être calculées
    				pool = multiprocessing.Pool()				#On réinitialise le pooleur
    				liste_res = []						#On vide la liste des lignes qui ont déjà étés calculées
    		pool.close()								#Validation des dernières lignes
    		pool.join()								#Lancement des derniers calculs
    		matrice.extend([resultat.get() for resultat in liste_res])		#Récupération des derniers résultats
    		return None
    Voici mon code encore plus épuré.

    Je croyait que '__main__' était juste une valeur que prenait la variable name si le programme est lancé depuis l’extérieur. Pourquoi il cherche une variable 'calcul' dans un module??? Cela fait que 1 an que je code et encore beaucoup de choses m'échappent! Du coup, il faut faire quoi pour lui faire comprendre que la variable calcul se trouve dans le programme et pas dans un module (si c'est bien comme ça qu'il faut réparer le bug!) ou bien, comment créer un lien dans le module '__main__' qui mène vers la véritable fonction calcul?

  7. #7
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 752
    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 752
    Par défaut
    Citation Envoyé par Robin Richard Voir le message
    Du coup, il faut faire quoi pour lui faire comprendre que la variable calcul se trouve dans le programme et pas dans un module (si c'est bien comme ça qu'il faut réparer le bug!) ou bien, comment créer un lien dans le module '__main__' qui mène vers la véritable fonction calcul?
    "calcul" est variable locale de la fonction "calculage_rapide" parce que fonction définie à l'intérieur d'une autre fonction. Faites en une fonction "normale" et çà ira mieux.
    note: multiprocessing vous impose de travailler sur des objets "pickable" (ou de les rendre pickable). Une fonction incluse dans une autre fonction ne l'est pas:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    >>> import pickle
    >>> def f():
    ...     def g(): pass
    ...     pickle.dumps(g)
    ...
    >>> f()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 3, in f
    _pickle.PicklingError: Can't pickle <function f.<locals>.g at 0x0000000002D8A9D8
    >: attribute lookup g on __main__ failed
    >>>
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

Discussions similaires

  1. [Python 3.X] Ajouter des Labels/Buttons sur une fenetre dans une def
    Par RetardedGenji dans le forum Tkinter
    Réponses: 3
    Dernier message: 10/06/2017, 12h55
  2. Réponses: 11
    Dernier message: 29/04/2016, 12h15
  3. [Python 2.X] Déclaration d'un tableau dans une Class MaClass \ def
    Par macErmite dans le forum Général Python
    Réponses: 3
    Dernier message: 26/07/2015, 08h53
  4. Inclure un .def dans une dll
    Par wanchy dans le forum Eclipse C & C++
    Réponses: 0
    Dernier message: 23/07/2009, 09h45
  5. gérer les jpg dans une fenetre directdraw???
    Par Anonymous dans le forum DirectX
    Réponses: 1
    Dernier message: 14/06/2002, 13h39

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