[Python] Variable global ?
Résolu/Fermé
BoBoX
-
24 juin 2008 à 18:29
sebsauvage Messages postés 32893 Date d'inscription mercredi 29 août 2001 Statut Modérateur Dernière intervention 21 octobre 2019 - 3 juil. 2008 à 14:46
sebsauvage Messages postés 32893 Date d'inscription mercredi 29 août 2001 Statut Modérateur Dernière intervention 21 octobre 2019 - 3 juil. 2008 à 14:46
A voir également:
- [Python] Variable global ?
- Citizen code python - Guide
- Python retour à la ligne dans le code - Forum Python
- Global no.2 lcd tv brand - Forum TV & Vidéo
- Ce programme est écrit en python. il construit un mot secret dans une variable mais il ne l'affiche pas. modifiez-le pour qu'il affiche le mot secret. exécutez-le. quel est ce mot secret ? ✓ - Forum Python
- Global postal shipping - Forum Consommation & Internet
14 réponses
sebsauvage
Messages postés
32893
Date d'inscription
mercredi 29 août 2001
Statut
Modérateur
Dernière intervention
21 octobre 2019
15 655
25 juin 2008 à 11:22
25 juin 2008 à 11:22
Les interfaces graphiques ne sont pas thread-safe !
Deux thread ne doivent jamais essayer de modifier les interfaces graphiques en même temps.
Sinon c'est le plantage assuré.
Voilà comment j'ai procédé pour WebGobbler:
J'ai un thread pour l'interface graphique, et un autre pour le réseau (et d'autres pour les traitements d'image).
Les threads communiquent entre eux grâce à un objet Queue commun.
Dans cet objet queue les threads déposent et lisent des messages (des objets).
L'objet Queue étant thread-safe, aucun risque.
Quand le thread réseau a fini son travail ou reçoit un évènement, il dépose un message (un objet, en fait, avec toutes les infos qui vont bien) dans la Queue.
Le thread de ma GUI regarde régulièrement dans la Queue s'il y a des messages, et réagit en conséquence (mise à jour de widgets ,etc.)
Ainsi, il y a un seul thread qui accède aux widgets: Aucun risque de plantage, aucune section critique à gérer.
L'objet Queue simplifie grandement la programmation multi-threads.
Deux thread ne doivent jamais essayer de modifier les interfaces graphiques en même temps.
Sinon c'est le plantage assuré.
Voilà comment j'ai procédé pour WebGobbler:
J'ai un thread pour l'interface graphique, et un autre pour le réseau (et d'autres pour les traitements d'image).
Les threads communiquent entre eux grâce à un objet Queue commun.
Dans cet objet queue les threads déposent et lisent des messages (des objets).
L'objet Queue étant thread-safe, aucun risque.
Quand le thread réseau a fini son travail ou reçoit un évènement, il dépose un message (un objet, en fait, avec toutes les infos qui vont bien) dans la Queue.
Le thread de ma GUI regarde régulièrement dans la Queue s'il y a des messages, et réagit en conséquence (mise à jour de widgets ,etc.)
Ainsi, il y a un seul thread qui accède aux widgets: Aucun risque de plantage, aucune section critique à gérer.
L'objet Queue simplifie grandement la programmation multi-threads.
sebsauvage
Messages postés
32893
Date d'inscription
mercredi 29 août 2001
Statut
Modérateur
Dernière intervention
21 octobre 2019
15 655
25 juin 2008 à 11:45
25 juin 2008 à 11:45
Pour ré-expliquer les choses autrement:
Il y a un objet Queue commun à mes différents threads.
Quand l'utilisateur clic dans l'interface graphique, le thread en charge de la GUI place un message dans la Queue. Ce message veut dire "Va me chercher trucmuche".
Le thread qui s'occupe du réseau lit ce message, fait ce qu'on lui demande, et quand il a fini il place le résultat dans la Queue.
De son côté, le thread de la GUI regarde temps en temps dans la Queue s'il y a une réponse.
Quand il a une réponse, il l'affiche en mettant à jour l'interface graphique (zone de texte).
En créant des objets message, on peut véhiculer des messages, commandes et résultats entre les différents threads.
Chaque thread peut très bien être programmé pour ne réagir qu'à certains types de messages.
Il y a un objet Queue commun à mes différents threads.
Quand l'utilisateur clic dans l'interface graphique, le thread en charge de la GUI place un message dans la Queue. Ce message veut dire "Va me chercher trucmuche".
Le thread qui s'occupe du réseau lit ce message, fait ce qu'on lui demande, et quand il a fini il place le résultat dans la Queue.
De son côté, le thread de la GUI regarde temps en temps dans la Queue s'il y a une réponse.
Quand il a une réponse, il l'affiche en mettant à jour l'interface graphique (zone de texte).
En créant des objets message, on peut véhiculer des messages, commandes et résultats entre les différents threads.
Chaque thread peut très bien être programmé pour ne réagir qu'à certains types de messages.
# -*- coding: Latin-1 -*-
import wx
import socket
import os, sys, time
from threading import Thread
HOST='127.0.0.1'
PORT=1502
global frame
class GUI(wx.Frame):
def __init__(self,parent,id,title):
wx.Frame.__init__(self,parent,id,title,size=(650, 500))
self.connected=False
hbox=wx.BoxSizer(wx.HORIZONTAL)
self.text = wx.TextCtrl(self, 1000, '', size=(-1, -1), style=wx.TE_MULTILINE | wx.TE_PROCESS_ENTER)
self.text.SetFocus()
self.text.SetEditable(False)
self.display = wx.TextCtrl(self, -1, '',size=(550, 30))
buttonSend=wx.Button(self,801,"Envoyer")
hbox.Add(self.display,0)
hbox.Add(buttonSend,1,wx.EXPAND)
self.sizer=wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(self.text,1,wx.EXPAND)
self.sizer.Add(hbox,0,wx.EXPAND)
self.SetSizer(self.sizer)
self.Bind(wx.EVT_BUTTON, self.SendMsg, id=801)
self.Bind(wx.EVT_KEY_UP, self.OnChar)
self.Centre()
self.Show()
self.ConnectTo()
def updatetxt(self,msg):
self.msg=msg
self.text.SetEditable(True)
self.text.AppendText('\n'+self.msg)
self.text.SetEditable(False)
def OnChar(self,event):
cle=event.GetKeyCode()
if cle == 13 :
self.SendMsg(None)
def ConnectTo(self):
self.connected=True
self.connection=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
try :
self.connection.connect((HOST,PORT))
except socket.error :
print "La connexion à échoué ",HOST," ",PORT
sys.exit()
thR=ThreadReception(self.connection)
thR.start()
def SendMsg(self,event):
if self.connected is True :
message=self.display.GetValue()
self.connection.send(message)
self.display.Clear()
else :
pass
class ThreadReception(Thread):
def __init__(self,connec):
Thread.__init__(self)
self.Terminated=False
self.connexion=connec
def run(self):
while True :
msgserver=self.connexion.recv(1024)
if msgserver=='QUIT' :
self.connexion.close()
break
frame.updatetxt(msgserver)
App=wx.App()
frame=GUI(None,-1,"Client")
App.MainLoop()
import wx
import socket
import os, sys, time
from threading import Thread
HOST='127.0.0.1'
PORT=1502
global frame
class GUI(wx.Frame):
def __init__(self,parent,id,title):
wx.Frame.__init__(self,parent,id,title,size=(650, 500))
self.connected=False
hbox=wx.BoxSizer(wx.HORIZONTAL)
self.text = wx.TextCtrl(self, 1000, '', size=(-1, -1), style=wx.TE_MULTILINE | wx.TE_PROCESS_ENTER)
self.text.SetFocus()
self.text.SetEditable(False)
self.display = wx.TextCtrl(self, -1, '',size=(550, 30))
buttonSend=wx.Button(self,801,"Envoyer")
hbox.Add(self.display,0)
hbox.Add(buttonSend,1,wx.EXPAND)
self.sizer=wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(self.text,1,wx.EXPAND)
self.sizer.Add(hbox,0,wx.EXPAND)
self.SetSizer(self.sizer)
self.Bind(wx.EVT_BUTTON, self.SendMsg, id=801)
self.Bind(wx.EVT_KEY_UP, self.OnChar)
self.Centre()
self.Show()
self.ConnectTo()
def updatetxt(self,msg):
self.msg=msg
self.text.SetEditable(True)
self.text.AppendText('\n'+self.msg)
self.text.SetEditable(False)
def OnChar(self,event):
cle=event.GetKeyCode()
if cle == 13 :
self.SendMsg(None)
def ConnectTo(self):
self.connected=True
self.connection=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
try :
self.connection.connect((HOST,PORT))
except socket.error :
print "La connexion à échoué ",HOST," ",PORT
sys.exit()
thR=ThreadReception(self.connection)
thR.start()
def SendMsg(self,event):
if self.connected is True :
message=self.display.GetValue()
self.connection.send(message)
self.display.Clear()
else :
pass
class ThreadReception(Thread):
def __init__(self,connec):
Thread.__init__(self)
self.Terminated=False
self.connexion=connec
def run(self):
while True :
msgserver=self.connexion.recv(1024)
if msgserver=='QUIT' :
self.connexion.close()
break
frame.updatetxt(msgserver)
App=wx.App()
frame=GUI(None,-1,"Client")
App.MainLoop()
sebsauvage
Messages postés
32893
Date d'inscription
mercredi 29 août 2001
Statut
Modérateur
Dernière intervention
21 octobre 2019
15 655
25 juin 2008 à 11:31
25 juin 2008 à 11:31
Voir: http://docs.python.org/lib/QueueObjects.html
Vous n’avez pas trouvé la réponse que vous recherchez ?
Posez votre question
BoBoXx
Messages postés
260
Date d'inscription
mardi 24 juin 2008
Statut
Membre
Dernière intervention
3 août 2008
34
25 juin 2008 à 18:20
25 juin 2008 à 18:20
Merci sebsauvage ! grâce à tes explications je vais enfin pouvoir progresser. :D
Mais si je fait une verification tout les temps et temps la GUI va ce bloqué non ?
Ah moin que je puisse mettre une fonction Thread dans la classe GUI.
Je vais essayer de suite :p
Mais si je fait une verification tout les temps et temps la GUI va ce bloqué non ?
Ah moin que je puisse mettre une fonction Thread dans la classe GUI.
Je vais essayer de suite :p
sebsauvage
Messages postés
32893
Date d'inscription
mercredi 29 août 2001
Statut
Modérateur
Dernière intervention
21 octobre 2019
15 655
25 juin 2008 à 20:49
25 juin 2008 à 20:49
Mais si je fait une verification tout les temps et temps la GUI va ce bloqué non ?
Non, on peut ruser.
Tkinter permet de déclencher l'appel d'une méthode après un délai donné.
Par exemple, dans ton IHM:
self.timerCollectorsStatus = self._parent.after(250, self._updateCollectorStatus)
La méthode self._updateCollectorStatus sera appelée dans 250 ms (environ, si rien n'occupe la GUI).
Dans la méthode self._updateCollectorStatus, on lit la queue pour un éventuel message, on fait les traitements qui vont bien (mise à jour des widgets), puis on ré-arme le timer (même instruction).
On peut ainsi demander à l'interface graphique de faire des vérifications régulièrement.
La lecture de l'objet Queue peut être (au choix) bloquant ou non.
En l'utilisant en non-bloquant, il rend la main immédiatement si aucun objet n'est disponible dans la queue.
Non, on peut ruser.
Tkinter permet de déclencher l'appel d'une méthode après un délai donné.
Par exemple, dans ton IHM:
self.timerCollectorsStatus = self._parent.after(250, self._updateCollectorStatus)
La méthode self._updateCollectorStatus sera appelée dans 250 ms (environ, si rien n'occupe la GUI).
Dans la méthode self._updateCollectorStatus, on lit la queue pour un éventuel message, on fait les traitements qui vont bien (mise à jour des widgets), puis on ré-arme le timer (même instruction).
On peut ainsi demander à l'interface graphique de faire des vérifications régulièrement.
La lecture de l'objet Queue peut être (au choix) bloquant ou non.
En l'utilisant en non-bloquant, il rend la main immédiatement si aucun objet n'est disponible dans la queue.
BoBoXx
Messages postés
260
Date d'inscription
mardi 24 juin 2008
Statut
Membre
Dernière intervention
3 août 2008
34
27 juin 2008 à 20:14
27 juin 2008 à 20:14
Voila j'ai fait ce que tu ma dit et ça fonctionne à merveille =)
reste plus qu' a régler le problème de l'encode lors du message.send(message) (ça je sais fair ^^)
Par contre j'ai un autre problème si je lance le client il va se connecté automatiquement mais lorsque je kill le processus le serveur rentre dans une boucle infinie et je suis obligé de le kill à son tour
reste plus qu' a régler le problème de l'encode lors du message.send(message) (ça je sais fair ^^)
Par contre j'ai un autre problème si je lance le client il va se connecté automatiquement mais lorsque je kill le processus le serveur rentre dans une boucle infinie et je suis obligé de le kill à son tour
sebsauvage
Messages postés
32893
Date d'inscription
mercredi 29 août 2001
Statut
Modérateur
Dernière intervention
21 octobre 2019
15 655
27 juin 2008 à 22:29
27 juin 2008 à 22:29
Je suis content que ça marche :-))
Sur ton serveur tu as plusieurs threads ?
Dans ce cas, il faut absolument que lors de la fermeture de l'application, le thread principale envoie un message aux autres threads leur demandant de mourir.
Même chose dans l'interface graphique, sinon ton interface graphique ne fermera jamais, ou bien fermera mais le processus restera en mémoire (car il y a encore un thread vivant).
C'est un des inconvenients de Python: le thread principal ne peut pas tuer les autres threads. Il faut qu'ils meurent tout seul ou qu'on leur demande de mourir (avec un message spécial).
Si ton serveur est en train de recevoir des données et que le client est killé, il est possible qu'il attende indéfiniment des données.
Dans ce cas, il faut faire un timeout sur le revc (ou tout autre méthode) et le thread gérant ce client doit décider de mourir s'il n'a pas reçu de données depuis x temps.
Note que pour un client serveur, je déconseille fortement d'utiliser directement les sockets, car ça pose divers problème (comment détecter qu'un client est mort, comment savoir si la réception des données est terminée, etc.).
On peut très utiliser, au lieu d'utiliser les sockets bruts, utiliser tout simplement HTTP.
C'est très efficace et facile à programmer (Python est fourni avec des serveurs et clients HTTP).
On peut aussi faire du XML-RPC, très sympa aussi (tu appelle juste une méthode sur un objet, et la méthode est automatiquement exécutée sur le serveur distant.)
Sur ton serveur tu as plusieurs threads ?
Dans ce cas, il faut absolument que lors de la fermeture de l'application, le thread principale envoie un message aux autres threads leur demandant de mourir.
Même chose dans l'interface graphique, sinon ton interface graphique ne fermera jamais, ou bien fermera mais le processus restera en mémoire (car il y a encore un thread vivant).
C'est un des inconvenients de Python: le thread principal ne peut pas tuer les autres threads. Il faut qu'ils meurent tout seul ou qu'on leur demande de mourir (avec un message spécial).
Si ton serveur est en train de recevoir des données et que le client est killé, il est possible qu'il attende indéfiniment des données.
Dans ce cas, il faut faire un timeout sur le revc (ou tout autre méthode) et le thread gérant ce client doit décider de mourir s'il n'a pas reçu de données depuis x temps.
Note que pour un client serveur, je déconseille fortement d'utiliser directement les sockets, car ça pose divers problème (comment détecter qu'un client est mort, comment savoir si la réception des données est terminée, etc.).
On peut très utiliser, au lieu d'utiliser les sockets bruts, utiliser tout simplement HTTP.
C'est très efficace et facile à programmer (Python est fourni avec des serveurs et clients HTTP).
On peut aussi faire du XML-RPC, très sympa aussi (tu appelle juste une méthode sur un objet, et la méthode est automatiquement exécutée sur le serveur distant.)
BoBoXx
Messages postés
260
Date d'inscription
mardi 24 juin 2008
Statut
Membre
Dernière intervention
3 août 2008
34
28 juin 2008 à 14:17
28 juin 2008 à 14:17
Non sur mon serveur je n'ai qu'un thread et j'ai mit des message pour que les threads s'arrete.
CLIENT
Et pour le serveur :
Voila c'est ça que je comprend pas en faite ^^ Ca fonctionne bien si depuis le client j'envoie la commande 'QUIT' alors les threads s'arrete des 2 cotés mais si je le kill sauvagement bah ... ^^
J'ai vais essayer de mettre un timeout =)
Sinon bah je le ferais en http mais le problème c'est que je ne sait pas véhiculer des messages à travers celui-ci.
J'ai juste réussi a faire un petit serveur Http en LAN pour transferer des données sur 2 OS différent
CLIENT
def OnDeco(self): self.thR.stop() self.connection.close() self.thR.join() self.thR=None self.updatetxt("Vous êtes maintenant déconnecté") self.connected=False def on_timer(self,event): try : msg=msgStock.get_nowait() if msg == 'QUIT' : self.OnDeco() elif msg == 'EXIT' : try : self.OnDeco() except : pass self.Destroy() else : self.updatetxt(msg) except : pass
Et pour le serveur :
class ThreadClient(Thread): def __init__(self,connexion): Thread.__init__(self) self.connexion=connexion def run(self): nom=self.getName() while 1 : msgclient=self.connexion.recv(1024) if msgclient == 'QUIT' : for i in nbrclient : nbrclient[i].send(msgclient) break else : print nom,msgclient for i in nbrclient : nbrclient[i].send(msgclient) self.connexion.close() del nbrclient[nom] print "Client %s déconnecté" %(nom)
Voila c'est ça que je comprend pas en faite ^^ Ca fonctionne bien si depuis le client j'envoie la commande 'QUIT' alors les threads s'arrete des 2 cotés mais si je le kill sauvagement bah ... ^^
J'ai vais essayer de mettre un timeout =)
Sinon bah je le ferais en http mais le problème c'est que je ne sait pas véhiculer des messages à travers celui-ci.
J'ai juste réussi a faire un petit serveur Http en LAN pour transferer des données sur 2 OS différent
sebsauvage
Messages postés
32893
Date d'inscription
mercredi 29 août 2001
Statut
Modérateur
Dernière intervention
21 octobre 2019
15 655
29 juin 2008 à 00:31
29 juin 2008 à 00:31
HTTP ou XML-RPC sont très pratique.
pkmaide
Messages postés
132
Date d'inscription
vendredi 21 mars 2008
Statut
Membre
Dernière intervention
22 septembre 2008
9
30 juin 2008 à 00:15
30 juin 2008 à 00:15
comment a tu fait pour installer python car chez moi sa ne marche pas.aide moi stp.
BoBoXx
Messages postés
260
Date d'inscription
mardi 24 juin 2008
Statut
Membre
Dernière intervention
3 août 2008
34
30 juin 2008 à 06:07
30 juin 2008 à 06:07
Polue pas mon sujet ...
sebsauvage
Messages postés
32893
Date d'inscription
mercredi 29 août 2001
Statut
Modérateur
Dernière intervention
21 octobre 2019
15 655
30 juin 2008 à 09:19
30 juin 2008 à 09:19
Pour en revenir à XML-RPC, j'ai trouvé une bonne page qui explique ça:
https://www.ibm.com/fr-fr
Cette page comporte un exemple tout simple: Le client demande le calendrier d'un mois précis, et le serveur lui envoie:
Le serveur:
Et le cilent:
Ce qui est remarquable, c'est la simplicité coté client: On déclare juste un serveur et on appelle une fonction sur le serveur.
Cela simplifie grandement les choses.
https://www.ibm.com/fr-fr
Cette page comporte un exemple tout simple: Le client demande le calendrier d'un mois précis, et le serveur lui envoie:
Le serveur:
import calendar, SimpleXMLRPCServer class Calendar: def getMonth(self, year, month): return calendar.month(year, month) def getYear(self, year): return calendar.calendar(year) calendar_object = Calendar() server = SimpleXMLRPCServer.SimpleXMLRPCServer(("localhost", 8888)) server.register_instance(calendar_object) print "Listening on port 8888" server.serve_forever()
Et le cilent:
import xmlrpclib server = xmlrpclib.ServerProxy("http://localhost:8888") month = server.getMonth(2002, 8) print month
Ce qui est remarquable, c'est la simplicité coté client: On déclare juste un serveur et on appelle une fonction sur le serveur.
Cela simplifie grandement les choses.
sebsauvage
Messages postés
32893
Date d'inscription
mercredi 29 août 2001
Statut
Modérateur
Dernière intervention
21 octobre 2019
15 655
30 juin 2008 à 10:18
30 juin 2008 à 10:18
Tiens tant qu'on y est, j'ai mis un exemple encore plus simple de client/serveur XML-RPC sur mon site:
https://sebsauvage.net/python/snyppets/index.html#xmlrpc
https://sebsauvage.net/python/snyppets/index.html#xmlrpc
BoBoXx
Messages postés
260
Date d'inscription
mardi 24 juin 2008
Statut
Membre
Dernière intervention
3 août 2008
34
3 juil. 2008 à 13:09
3 juil. 2008 à 13:09
Voila j'ai fait un serveur xml-rpc selon les exemples.
Je dois dir que je suis trés étonné de la longueur du code ^^
le problème se situe du coté client après
Je dois dir que je suis trés étonné de la longueur du code ^^
# -*- coding: Latin-1 -*- import SimpleXMLRPCServer class ServeurChat(): def sendmessage(self,msg): print msg self.message=msg def rmessage(self): return self.message self.message='NONE-MSG' chat_objet=ServeurChat() server = SimpleXMLRPCServer.SimpleXMLRPCServer(("localhost", 8888)) server.register_instance(chat_objet) print "Listening on port 8888" server.serve_forever()
le problème se situe du coté client après
sebsauvage
Messages postés
32893
Date d'inscription
mercredi 29 août 2001
Statut
Modérateur
Dernière intervention
21 octobre 2019
15 655
>
BoBoXx
Messages postés
260
Date d'inscription
mardi 24 juin 2008
Statut
Membre
Dernière intervention
3 août 2008
3 juil. 2008 à 13:15
3 juil. 2008 à 13:15
je suis trés étonné de la longueur du code
Sympa, hein ? :-)
le problème se situe du coté client après
Des soucis ? Des message d'erreur ?
Sympa, hein ? :-)
le problème se situe du coté client après
Des soucis ? Des message d'erreur ?
BoBoXx
Messages postés
260
Date d'inscription
mardi 24 juin 2008
Statut
Membre
Dernière intervention
3 août 2008
34
>
sebsauvage
Messages postés
32893
Date d'inscription
mercredi 29 août 2001
Statut
Modérateur
Dernière intervention
21 octobre 2019
3 juil. 2008 à 14:06
3 juil. 2008 à 14:06
Oui, dans le client j'ai un thread qui appelle la fonction rmessage() régulierement (plusieurs fois par seconde) et le problème c'est qu'il update à chaque fois mon widget text même en essayant de mettre des protections.
Je suis un peu perdue la, si jamais ta une solution :)
Je suis un peu perdue la, si jamais ta une solution :)
class ThreadReception(Thread): def __init__(self,connec): Thread.__init__(self) self.Terminated=False self.connexion=connec self.MSG=None def run(self): while not self.Terminated : try : msgserver=self.connexion.rmessage() if self.MSG == msgserver : pass else : msgStock.put_nowait(msgserver) print msgserver self.MSG=msgserver except : pass def stop(self): self.Terminated=True
BoBoXx
Messages postés
260
Date d'inscription
mardi 24 juin 2008
Statut
Membre
Dernière intervention
3 août 2008
34
>
sebsauvage
Messages postés
32893
Date d'inscription
mercredi 29 août 2001
Statut
Modérateur
Dernière intervention
21 octobre 2019
3 juil. 2008 à 14:22
3 juil. 2008 à 14:22
J'ai trouvé la solution ! =)
j'ai rajouter un del
et voila sa ne bug plus :)
j'ai rajouter un del
def rmessage(self): return self.message del self.message
et voila sa ne bug plus :)
sebsauvage
Messages postés
32893
Date d'inscription
mercredi 29 août 2001
Statut
Modérateur
Dernière intervention
21 octobre 2019
15 655
3 juil. 2008 à 14:46
3 juil. 2008 à 14:46
Content que ça marche :-))