Je répondais à Jurassik, comme le montre le fait que je l'avais cité au préalable ;)
Version imprimable
Je répondais à Jurassik, comme le montre le fait que je l'avais cité au préalable ;)
Petite question:
quand ma fonction vise à retourner un tuple de dictionnaires, je la définis bien comme suit pour Cython:
Parce que la cythonisation me renvoie ceci:Code:
1
2
3
4
5
6
7
8 cpdef (dict, dict, dict, dict) etude_proprietaire_moy_quinte(self, variable1, variable 2 ....): . . . return dico1, dico2, dico3, dico4
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 Error compiling Cython file: ------------------------------------------------------------ ... #### PROPRIÉTAIRES # VALEUR 20 cpdef (dict, dict, dict, dict) etude_proprietaire_moy_quinte(self, param, choixProno, dico_points_base, dico_points_discipline,dico_points_similaire, dico_points_similaire_inscrits,\ ^ ------------------------------------------------------------ prog_principal.py:8417:35: Syntax error in simple statement list Traceback (most recent call last): File "/Users/stef/Desktop/Pronostef 2/setup.py", line 15, in <module> ext_modules = cythonize(extensions), File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/Cython/Build/Dependencies.py", line 1102, in cythonize cythonize_one(*args) File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/Cython/Build/Dependencies.py", line 1225, in cythonize_one raise CompileError(None, pyx_file) Cython.Compiler.Errors.CompileError: prog_principal.py
Une autre difficulté que je ne comprends pas, c'est que lorsque je lance une cythonisation avec l'extension .pyx , j'obtiens un message d'erreur:
donneCode:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 from distutils.core import setup from distutils.extension import Extension from Cython.Build import cythonize from Cython.Distutils import build_ext # extensions = [ Extension("prog_principal", ["prog_principal.pyx"]) # à renommer selon les besoins # ] extensions = [ Extension("prog_principal", ["prog_principal.pyx"]) # à renommer selon les besoins ] setup( cmdclass = {'build_ext':build_ext}, ext_modules = cythonize(extensions), )
tandis que si j'utilise:Code:
1
2
3
4
5
6
7
8
9
10
11
12
13 python3 setup.py build_ext --inplace Traceback (most recent call last): File "/Users/stef/Desktop/Pronostef 2/setup.py", line 15, in <module> ext_modules = cythonize(extensions), File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/Cython/Build/Dependencies.py", line 965, in cythonize module_list, module_metadata = create_extension_list( File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/Cython/Build/Dependencies.py", line 815, in create_extension_list for file in nonempty(sorted(extended_iglob(filepattern)), "'%s' doesn't match any files" % filepattern): File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/Cython/Build/Dependencies.py", line 114, in nonempty raise ValueError(error_msg) ValueError: 'prog_principal.pyx' doesn't match any files
la cythonisation débutera et donnera:Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 from distutils.core import setup from distutils.extension import Extension from Cython.Build import cythonize from Cython.Distutils import build_ext # extensions = [ Extension("prog_principal", ["prog_principal.pyx"]) # à renommer selon les besoins # ] extensions = [ Extension("prog_principal", ["prog_principal.py"]) # à renommer selon les besoins ] setup( cmdclass = {'build_ext':build_ext}, ext_modules = cythonize(extensions), )
soit mon message d'erreur de tout à l'heure.Code:
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 python3 setup.py build_ext --inplace Compiling prog_principal.py because it changed. [1/1] Cythonizing prog_principal.py /Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/Cython/Compiler/Main.py:369: FutureWarning: Cython directive 'language_level' not set, using 2 for now (Py2). This will change in a later release! File: /Users/stephanebraem/Desktop/Pronostef 2/prog_principal.py tree = Parsing.p_module(s, pxd, full_module_name) Error compiling Cython file: ------------------------------------------------------------ ... #### PROPRIÉTAIRES # VALEUR 20 cpdef (dict, dict, dict, dict) etude_proprietaire_moy_quinte(self, param, choixProno, dico_points_base, dico_points_discipline,dico_points_similaire, dico_points_similaire_inscrits,\ ^ ------------------------------------------------------------ prog_principal.py:8417:35: Syntax error in simple statement list Traceback (most recent call last): File "/Users/stef/Desktop/Pronostef 2/setup.py", line 15, in <module> ext_modules = cythonize(extensions), File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/Cython/Build/Dependencies.py", line 1102, in cythonize cythonize_one(*args) File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/Cython/Build/Dependencies.py", line 1225, in cythonize_one raise CompileError(None, pyx_file) Cython.Compiler.Errors.CompileError: prog_principal.py
Merci
hello,
il me semble qu'avec l'extension py , le fichier est considéré comme un script python et python ne comprend pas les syntaxes avec cpdef, cdef
et pour le premier problème il faudrait commencer doucement avec des cas de variables simples et avec la remarque à Tyrtamos :
J'ai vu également des requêtes SQL dans ton code . Avec un profiler il faudrait savoir exactement où est perdu le temps : parce qu'il y a beaucoup de boucles ? parce qu'il y a une fonction lente dans la boucle ? etc ... ?Citation:
Quant à gagner du temps d'exécution avec la compilation par cython, attention à un détail: on gagne vraiment du temps lorsque le type des variables python passées au code C ou C++, existe en C ou C++! Sinon, le code compilé devra appeler l'API Python souvent, et le gain de temps ne sera pas présent, et même pourra être moins bon qu'avec le Python pur (ça m'est déjà arrivé).
Ami calmant, J.P
J'ai isolé la partie que je souhaité accélérer donc en plaçant celle-ci dans une fonction, dans un module.
Je n'arrive toujours pas à cythoniser cette fonction.
Le terminal me retourne toujoursalors que module_moyProprioFct.pyx est bel et bien présent dans mon dossierCode:
1
2 ValueError: 'module_moyProprioFct.pyx' doesn't match any files
et que mon setup.py est comme ceci:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13 from distutils.core import setup from distutils.extension import Extension from Cython.Build import cythonize from Cython.Distutils import build_ext extensions = [ Extension("module_moyProprioFct", ["module_moyProprioFct.pyx"]) setup( cmdclass = {'build_ext':build_ext}, ext_modules = cythonize(extensions), )
Je ne pige pas d'où vient le pb.
hello,
comme on peut le constater dans les traces d'erreur le problème provient de cette ligne dans le fichier Dependencies.py de Cython
si on regarde ce que fait nonempty il vérifie que le pattern correspond à un ou des fichiers existants (si il y a un joker comme *).Code:for file in nonempty(sorted(extended_iglob(filepattern)), "'%s' doesn't match any files" % filepattern):
normalement cela devrait marcher pour toi car le fichier module_moyProprioFct.pyx (qui s'affiche d'ailleurs dans le message d'erreur) existe.
Si il y a un problème c'est certainement dans la fonction extended_iglob de Dependencies.py à cet endroit :
avec un iglob(pattern) qui ne contient rien. Mais cela reste des suppositions. Le mieux serait de faire un point d'arrêt sur la ligne en erreur et de voir ce qui se passe en descendant dans les fonctions appelées dans la ligne. Chez moi il n'y a pas d'erreur.Code:
1
2
3 else: for path in iglob(pattern): yield path
Peut être un souci avec les chemins utilisés pour ton code source.
Ami calmant, J.P
Je pense que je peux éliminer le soucis avec mon chemin d'accès car si je cythonise de façon minimaliste c'est à dire en laissant Cython faire le travail sur mon module laissé en python pur et nommé .py, la cythonisation fonctionne. J'obtiens fichiers .c et .so. Et le code fonctionne et s'accélère (pas encore assez à mon goût), j'ai vérifié en le mesurant avec perf_counter()
@jurassic pork
Ton intuition était la bonne.
Cython indiquait que le fichier était inexistant.
En réalité, quand je renommais le fichier en .pyx, il apparaissait effectivement renommée dans le dossier mais quand j'ai fait 'obtenir les informations' sur ce même fichier,
j'ai constaté qu'il était toujours de type 'script python' avec toujours un .py de sorte que le dossier portait ce type de nom 'module_moyProprioFct.pyx.py'
La procédure ne pouvait dès lors que planter.
Par contre, niveau gain de vitesse, c'est pas folichon. Je pense que ce sont mes requêtes répétées à sqlite qui freinent pas mal.
N'y aurait il pas un moyen de les accélérer ?
hello,
peux-tu nous donner quelques informations concernant les performances:
ex : temps d'exécution
temps espéré.
Nombre de requêtes sql effectuées dans l'exécution.
Nombre d'éléments dans la base de données.
etc..
Ami calmant, J.P
Une entrée sortie disque est 1000 fois plus lente qu'un accès mémoire.
Et le seul moyen d'accélérer la vitesse des entrées sorties sera d'en faire moins.
Ce qui me turlupine dans votre affaire, c'est le nombre de lignes de code que vous voulez compiler (20000). Bien qu'on ne mesure plus la productivité d'un programmeur aux nombres de lignes qu'il écrit, l'ordre de grandeur reste entre 50 et 100 lignes/jour...
Et une indication de 200 à 400 jours de boulot pour écrire toutes ces lignes.
Si vous n'avez pas passé ce temps à écrire votre code, l'optimiser, c'est d'abord retravailler du côté structures de données/algorithmes/séquences de traitements à défaut de l'avoir fait à l'étape de conception...).
Ce n'est qu'après avoir fait ce boulot qu'on identifie les traitements qui pourraient mériter d'être "compilés" (à défaut de pouvoir être repensés côté algo.).
- W
Il y a maintenant 2 ans, je débutais et découvrais : print('Hello world !')
Aujourd'hui, je discute dans un post avec 3 généraux 5 étoiles sur le forum informatique. Ça vous donne une idée du chemin parcouru.
Donc 50/100 lignes jour, ce n'est par mon rythme bien que je m'y attèle tous les jours mais je le fais à temps perdu bien que ce soit devenu un hobbies très très prenant car ça me plait.
Alors, mon programme n'est pas parfait (un peu d'indulgence, je viens de loin) - je suis le premier à indiquer que je vais l'améliorer (cf mon indication sur la longueur des noms de variables) . J'ai tout mon temps pour cela.
Comme j'ai bien compris que 20000 lignes à cythoniser, c'était trop, j'ai isolé dans une fonction la partie de code à cythoniser, ce qui a fonctionné. Mais comme je ne voyais pas une nette différence, j'ai demandé à ce forum s'il était possible d'accélérer mes requêtes sqlite.
J'ai très bien compris que lorsque mon code sera optimisé avec des algorithmes ciselés, la cythonisation sera l'ultime catalyseur à mon code mais je voulais tenter la cythonisation, pour voir.
Maintenant, je reviens sur le sujet des select sqlite.
J'ai lu sur ce forum qu'il était possible d'effectuer des insertions multiples de cette façon semble-t-il:
Alors je me demandais si, sur le plan de la comparaison, il était possible de faire la même chose non pas en INSERT mais en SELECT ? (mais je crois que je vais être invité à changer de sujet sur ce forum )Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 c.execute('BEGIN'] for ...: c.execute('INSERT INTO mots VALUES (?, ?)',[nMot, j]) c.execute('INSERT INTO phrases VALUES (?, ?)',[i, nMot]) # Pour par exemple commiter toutes les 50 000 lignes. if nb == 50000: c.execute('END'] conn.commit() c.execute('BEGIN'] conn.commit()
Si on écrit:
on exécute 2 requêtes SQL (l'une après l'autre) et qu'il s'agisse de requête INSERT/SELECT/UPDATE, ... çà fera toujours 2 requêtes.Code:
1
2 c.execute('INSERT INTO mots VALUES (?, ?)',[nMot, j]) c.execute('INSERT INTO phrases VALUES (?, ?)',[i, nMot])
Par contre dans le cas des INSERT, on gagnerait peut être à faire des bulk insert (.executemany) dans chaque table.
Pour revenir à la productivité du programmeur, elle est "faible" car il passe 70% du temps à concevoir et lire les documentations pour arriver à maîtriser ce qu'il va coder.
Il est manifeste que vous n'avez pas trop passé de temps à maîtriser cython ou sqlite avant de vous jeter à l'eau... C'est bien mais c'est discutable lorsqu'on écrit un gros programme et qu'on cherche à améliorer ses performances.
- W
Ce qui est manifeste, c'est que vous amalgamez forum et tribunal.
Vous n'êtes pas là pour voir le temps que j'ai pu passer à consulter la documentation.
C'est vrai que nous sommes dans le domaine de la programmation et je n'aurais pas pensé à consulter le web ou de la doc pour trouver réponse.
Clairement, les débutants vous posent des questions que vous devez estimer indigne de votre niveau
et je m'étonne de ne pas avoir lu votre phrase favorite (car j'ai lu plus d'une de vos publications):
"il y a des tutos pour ça".
J'ai pas fait tant de cinéma quand je vous ai repris sur une simple addition par le passé.
Quand on vient sur une forum, c'est pour avoir des réponses à une difficulté, pas pour recevoir un jugement de valeur.
Bon, vous m'avez convaincu car malheureusement à chaque fois je tombe sur vous, c'est décidé, je change de crémerie.
Je vais rester calme mais sachez que je vous donnerai la leçon dans bien des domaines autres que l'informatique .
Ingénieur ne veut vraiment pas dire génial. Loin de là.
Ciao pantin. (en plus vous avez répondu à côté de ma question, une fois de plus).
Il n'y a pas de réponses à vos difficultés car vous posez des questions sans contexte auxquelles on ne peut répondre qu'en vous renvoyant à la documentation.
Si vous avez commencé à jouer avec Python, il y a 2 ans et écrit 20000 de code, vous n'êtes plus débutant! Et si vous n'êtes plus débutant, çà veut dire que vous avez pris le temps de lire un peu la documentation, enrichir votre vocabulaire technique pour décrire les problèmes rencontrés, ...
Relisez votre dernière question:
Vous montrez une transaction qui s'assure que les 2 INSERT seront soit effectués complètement soit défaits (pour assurer l'intégrité de la base).Citation:
J'ai lu sur ce forum qu'il était possible d'effectuer des insertions multiples de cette façon semble-t-il:
Alors je me demandais si, sur le plan de la comparaison, il était possible de faire la même chose non pas en INSERT mais en SELECT ? (mais je crois que je vais être invité à changer de sujet sur ce forum )Code:
1
2
3
4
5
6
7
8
9
10
11
12 c.execute('BEGIN'] for ...: c.execute('INSERT INTO mots VALUES (?, ?)',[nMot, j]) c.execute('INSERT INTO phrases VALUES (?, ?)',[i, nMot]) # Pour par exemple commiter toutes les 50 000 lignes. if nb == 50000: c.execute('END'] conn.commit() c.execute('BEGIN'] conn.commit()
SELECT se contente de lire, pas besoin d'un contexte de transaction pour en faire plusieurs à la suite.
Que reste-t-il se sensé? La séquence des 2 .execute et la phrase "commiter toutes les 50 000 lignes", où j'essaie de vous expliquer que les bulk insert seraient bien plus efficace (et vous indiquer .executemany).
Ce n'est pas vous que je juge, je ne vous connais pas. Juste le travail que vous présentez... et si je pense que vous pourriez mieux faire en vous documentant, je ne vois pas pourquoi je ne le dirai pas.
Pour moi 70% du temps passé par un programmeur est dans la documentation et les petits tests pour s'assurer qu'on a compris sinon que çà fera ce qu'on attend. Vous suggérer d'ouvrir une documentation, de ne pas vous lancer dans des projets trop ambitieux trop tôt,... n'a rien de péjoratif: c'est juste du bon sens.
Si vous venez dans le coin, c'est pour essayer de vous améliorer pas pour avoir des trucs prêts à emporter... et zapper l'effort d'apprentissage.
Tous les humains peuvent se tromper.
Maintenant ne pas prendre le temps de se perfectionner et de s'équiper avant de se lancer dans l'escalade de l'Himalaya, n'est pas une erreur, c'est juste mal apprécier les moyens à se donner pour réaliser ses ambitions.... et mettre en danger la vie des secours de haute montagne parce qu'on fait son caprice.
- W