|
Publicité ' | |||||||||||||||||||||||
|
|
#1 | ||
|
Membre régulier
![]() Inscription : septembre 2003 Messages : 245 ![]() |
Bonjour,
Je suis en train de tester le threading sur python, et je rencontre quelque difficultés. Mon test est simple: Je voudrai qu'un thread fasse des insertions dans une base pendant que mon programme principal affiche ce qui a été introduit. Voilà en gros le code que je teste (j'ai viré toute la partie bdd car ça fonctionne bien sur cette partie). Code :
Auriez-vous une piste à me filer ? |
||
|
|
00
|
|
|
#2 | ||
|
Membre Expert
![]() ![]() Inscription : octobre 2008 Messages : 974 ![]() |
Salut,
C'est fait pour tourner conjointement avec ton code principal, justement. Et ton code fonctionne très bien d'ailleurs: Code :
|
||
|
|
00
|
|
|
#3 |
|
Expert Confirmé Sénior
![]() Inscription : juin 2008 Messages : 3 739 ![]() |
Salut,
Le partage d'une même connexion à la BDD entre plusieurs threads est spécifique à l'API (MySQLDB) tant côté support que mise en œuvre. - W
__________________
Architectures Post-Modernes |
|
|
00
|
|
|
#4 |
|
Membre régulier
![]() Inscription : septembre 2003 Messages : 245 ![]() |
En fait, pour la partie bdd, je ne m'en fais pas. à la limite, je re-crée une nouvelle connexion dans le thread, et zou ...
Ce que je ne comprends pas, c'est qu'au début du programme, il me dit bien que les threads ont été démarrés. Mais le reste du programme n'est pas exécuté tant que les threads ne sont pas terminés. Par exemple, si dans mon __main__ j'ai 2 start() pour démarrer 2 threads et que juste après je fais un print, le print ne s'affiche pas tant que les threads ne sont pas terminés. Par contre, c'est vrai que les 2 threads s'exécutent simultanément. Si je comprends bien, il faut donc que mon thread qui insère et celui qui fait les select tournent en parallèle et non, juste un thread pour l'insert et le select dans le __main__ après le start() du thread d'insertion ? Sinon, il va falloir que je buche sur le partage de ressource entre 2 threads car les 2 threads, à un moment donné, devront utiliser le même port série. Ne pouvant pas ouvrir 2 fois le port, je serai obligé de l'ouvrir dans le programme principal, et de partager mon objet sur les 2 threads. C'est possible ça ? |
|
|
00
|
|
|
#5 |
|
Membre Expert
![]() ![]() Inscription : octobre 2008 Messages : 974 ![]() |
Dans la question de départ il s'agit d'un seul thread.
Ce thread ne fonctionne pas comme attendu parce qu'il est mal utilisé. 1. Un thread doit être conçu comme une tâche unique. 2. Le code principal ne doit rien en attendre. 3. Il devrait (je ne dis pas il doit) disposer de toutes ses resources avant d'être lancé. 4. il faut le laisser mourir de sa mort naturelle. Le code exemple de mon post précédent remplit exactement la tâche décrite dans la question initiale. J'invite zerros à relire sa question. |
|
|
00
|
|
|
#6 | ||
|
Membre régulier
![]() Inscription : septembre 2003 Messages : 245 ![]() |
ok, après avoir fait quelques tests avec le code de VincsS (merci), le fonctionnement me convient, sauf que mes 2 threads doivent tourner en boucle. Du coup voici le code que j'ai fait, mais je suis encore confronté à plusieurs soucis:
1 - Le CPU monte d'un coup dès que je lance le démon 2 - Impossible d'arrêter les threads sans killer le process python Code :
Pourquoi est-ce que lorsque je fais CTR-C le programme ne s'arrête pas ? Pourquoi est-ce que le programme prend autant de ressources lorsqu'il tourne ? Il tourne aux alentours de 60% et monte même parfois à 99% de load cpu. Ce démon python tourne sur une raspberry pi doté d'un CPU arm. J'espère que vous pourrez m'aiguiller sur ce que je fais de mal ... |
||
|
|
00
|
|
|
#7 | |||
|
Expert Confirmé Sénior
![]() Inscription : juin 2008 Messages : 3 739 ![]() |
Citation:
Exemple: Code :
th.daemon = True permet de sortir du programme: il n'y a pas de mécanique pour arrêter la thread. Sans pause entre les différents passages, çà bouffe du CPU inutilement: on cherche dans la base de donnée sans rien trouver et on boucle. Le vrai sujet est pourquoi utiliser des threads: - çà ne sert à rien dans votre cas: les activités sont synchrones(*), - comme vous ne savez pas les utiliser vous accumulez les dépendances entre des difficultés: interroger le SGDB, lancer des taches, mettre cela en threads,... (*) watchSerial n'est qu'un cas particulier de watchEvt: plutôt que lancer une commande on détruit les event de type "Receive". - W
__________________
Architectures Post-Modernes |
|||
|
|
00
|
|
|
#8 |
|
Membre régulier
![]() Inscription : septembre 2003 Messages : 245 ![]() |
En fait le démon sera asynchrone au final. Actuellement, pour faire les tests j'envoi un insert depuis le watchEvt pour que le select de watchSerial puisse le "poper" et le détruire. Je fais ça car je n'ai pas encore fait la partie serial.
Au final, quand un événement sera récupérer dans watchEvt, notamment si c'est un événement de type serial, une donnée sera écrite dans un serial (/dev/ttyUSB0). L'appareil connecté sur ce serial va exécuter une action, puis renvoyer un status qui sera "traper" par le watchSerial et inséré en base avec le type Receive. Mais le matériel peut recevoir des ordres d'une autre source également, et le status de ces ordres doivent être insérés en base également. Les threads doivent tourner en boucle pour traiter les événements aussitôt qu'ils arrivent. Dans ce cas là, existe t il un autre moyen d'arriver à mes fins qu'utiliser les threads ? |
|
|
00
|
|
|
#9 |
|
Membre régulier
![]() Inscription : septembre 2003 Messages : 245 ![]() |
j'ai ajouté une tempo de 0.5s et le cpu tombe à 3. oufff. 0.5, ça ira très bien pour commencer.
Il me reste plus qu'à trouver une solution pour la partie arrêt des threads, et/ou carrément changer la manière de tout gérer en utilisant autre chose que les threads. Mais quoi ? |
|
|
00
|
|
|
#10 | |
|
Expert Confirmé Sénior
![]() Inscription : juin 2008 Messages : 3 739 ![]() |
Citation:
Si votre "fin" est de bouffer du temps CPU pour rien, vous y arriverez sûrement avec des threads. Si vous voulez que les délais de traitements soient bornés et inférieurs à 1/10 de milliseconde, il faut revoir le design. - W
__________________
Architectures Post-Modernes |
|
|
|
00
|
|
|
#11 | |
|
Expert Confirmé Sénior
![]() Inscription : juin 2008 Messages : 3 739 ![]() |
Citation:
Mais vous ne savez pas l'utiliser. Relisez ce que je vous ai déjà indiqué plus haut. - W
__________________
Architectures Post-Modernes |
|
|
|
00
|
|
|
#12 | ||||
|
Expert Confirmé
![]() ![]() Inscription : décembre 2007 Messages : 1 798 ![]() |
Bonjour,
Avec les threads, on fait à peu près ce qu'on veut, sauf à les arrêter "sauvagement". Mais la solution proposée ici (avec le while et le stop) fonctionne très bien. Il y a plusieurs choses qui me gènent dans le dernier code de zerros. - chaque thread cherche des données (select) et en efface (delete). Il n'est donc pas impossible qu'un thread essaie d'effacer des données qui viennent d'être effacées par un autre thread. Ce n'est pas logique. Même si le serveur accepte les accès concurrents, il faudrait que chaque thread commence et finisse son travail sans qu'un autre thread s'interpose sur les mêmes données: on fait ça avec un verrou! - les threads peuvent effectivement avoir un fonctionnement permanent au sein d'un programme, mais le fait que la seule façon de les arrêter est un Ctrl-C me choque un peu. Il faudrait, par exemple, que lorsqu'un thread ne trouve plus de données dans son "select", il génère lui-même son arrêt (fin de sa méthode "run"). - dernier point mineur, il ne devrait pas y avoir de "print" dans les threads, parce qu'il n'y a qu'un seul canal d'affichage (sys.stdout) que les threads et le "thread pricipal" doivent se partager. On devrait donc utiliser un verrou. Voilà un petit programme de test qui prend en compte le 1er point (le verrou sur la base de données): Code :
Code :
L'ordre d'intervention des thread dépend du caractère aléatoire des tâches de la boucle while qui ne se trouverait pas soumis au verrou sur la base de données. Si par contre il n'y a aucune tâche hors du bloc "acquire() ...release()", les threads interviendont toujours dans le même ordre. Dans ce cas, on se demande si les threads sont bien utilies ici... Et avec un Ctrl-C, le programme arrête proprement les 5 threads, et affiche à la fin que le programme est terminé.
__________________
Ne rien ranger permet d'observer la loi universelle d'entropie: l'inévitable convergence vers le chaos... Mes recettes python: http://www.jpvweb.com |
||||
|
|
00
|
|
|
#13 | ||
|
Expert Confirmé Sénior
![]() Inscription : juin 2008 Messages : 3 739 ![]() |
Salut,
Citation:
Ceci dit le code du thread watchSerial récupère les entrées de la table evt de type "Receive" alors que watchEvt s'occupe des types "Send", "Ring", "Sys": ce ne sont pas les mêmes données. Le traitement de watchSerial pourrait être intégré dans watchEvt qui s'occuperait en plus de ce type là. In fine, on a un thread qui fait tout de façon séquentielle et le programme principal qui attend qu'on tape "control-C". Citation:
Ce qui est en défaut, c'est le traitement des "control-C". J'espère que votre exemple lui permettra d'y voir plus clair. - W
__________________
Architectures Post-Modernes |
||
|
|
00
|
|
|
#14 |
|
Membre régulier
![]() Inscription : septembre 2003 Messages : 245 ![]() |
mouarff. je suis en train de décortiquer avec le manuel python lol.
Je reviens vous dire quand j'aurai compris et appliquer vos conseils merciii en tout cas. a très vite |
|
|
00
|
|
|
#15 |
|
Membre régulier
![]() Inscription : septembre 2003 Messages : 245 ![]() |
merci à vous !!! C'est impeccable. ç marche au poil. J'ai mis 0.5 pour libérer encore un peu plus de ressource, et j'ai utilisé les Event en lisant le tuto de developpez: http://python.developpez.com/faq/?page=Thread
Je reviendrai surement poser des questions sur le partage de ressources entre les threads. Merccciiiiiii |
|
|
00
|
Copyright © 2000-2013 - www.developpez.com