Bonjour à tou(te)s,
je m'amuse avec subprocess pour me perfectionner en python, et alors que je pensais avoir compris, je tombe sur un bec...
J'ai écrit un petit script qui créé un process (qui n'est autre que le même script avec le paramètre "slave" en +) et essaie de communiquer avec lui via stdin/stdout.
Et je constate que le process fils ne commence que quand le père a fini !
Voici le codeet la sortie
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 # encoding:latin1 import sys if sys.argv[-1] == 'slave' : #------------------------------ partie SLAVE -------------------------------------------- """process slave : renvoie ce qu'il reçoit jusqu'à ce qu'il reçoive "stop_slave".""" print 'slave starts' while 1 : command = raw_input() print 'slave received (%s)'%command if command == 'stop_slave' : break # PPALC : le slave a été stoppé (Protocole Propriétaire A La C...) print 'slave_stopped' # PPALC : pour stopper le thread du master else: #------------------------------ partie MASTER -------------------------------------------- import time,subprocess,threading class Process : '''Classe qui crée un process et permet de communiquer avec lui via send et receive''' def __init__(self,*command): '''La ligne de commande du process dans la liste command''' self.process = subprocess.Popen( command,stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.STDOUT,shell=False ) self.thread = threading.Thread( None,self._receive_loop ) self.received = [] self.lock = threading.Lock() #self.thread.daemon = True # si je laisse ça, le thread meurt avant même que le slave ne soit lancé et j'ai encore moins d'affichage... self.thread.start() time.sleep( 1 ) # laisse le temps au process de se lancer (ou pas... :-() def _receive_loop (self): '''thread en attente sur le stdout du process et qui permet de rendre le receive non bloquant''' while 1 : print 'thread is waiting' s = self.process.stdout.readline().strip('\n\r') print 'thread received "%s"'%s if s == 'slave_stopped' : break # PPALC : thread du master stoppé par le slave with self.lock : self.received += [s] print 'thread ends' def send ( self,data ): '''envoie la string data au process slave''' self.process.stdin.write( data+'\n' ) def receive ( self ): '''renvoie la liste des string reçues du process slave depuis le dernier appel''' with self.lock : res = self.received self.received = [] return res '''process master : crée le process 'slave', lui envoie 10 strings arbitraires et enfin "stop_slave".''' p = Process('python',sys.argv[0],'slave') # slave = master + paramètre 'slave' for i in xrange( 10 ) : time.sleep( 0.1 ) print 'master send "command_%d"'%i p.send('command_%d'%i ) for s in p.receive() : print 'master received "%s"'%s p.send('stop_slave') # PPALC : le master stoppe le slave print 'master ends'Comme on le voit, le process fils (slave) ne commence qu'après la fin du process père (master)...
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 thread is waiting master send "command_0" master send "command_1" master send "command_2" master send "command_3" master send "command_4" master send "command_5" master send "command_6" master send "command_7" master send "command_8" master send "command_9" master ends thread received "slave starts" thread is waiting thread received "slave received (command_0)" thread is waiting thread received "slave received (command_1)" thread is waiting thread received "slave received (command_2)" thread is waiting thread received "slave received (command_3)" thread is waiting thread received "slave received (command_4)" thread is waiting thread received "slave received (command_5)" thread is waiting thread received "slave received (command_6)" thread is waiting thread received "slave received (command_7)" thread is waiting thread received "slave received (command_8)" thread is waiting thread received "slave received (command_9)" thread is waiting thread received "slave received (stop_slave)" thread is waiting thread received "slave_stopped" thread ends Exception : cannot join current thread
J'ai essayé de jouer avec des sleep pour laisser le temps au fils de se lancer, mais rien n'y fait (même avec 10 sec).
Comment expliquer ce phénomène ?
Qu'ai-je raté ?
(ça fait déjà un moment que je triture mon code et arpente les fora, et je suis toujours à sec...)
Question subsidiaire (pour ceux ou celles qui auraient déjà résolu ce problème) :
Comment rendre plus propre la terminaison du fils (sans définir un protocole propriétaire à la c... avec base de string prédéfinie ("stop_slave" ici)).
Pour info, je tourne sous Windows 7 64 bits... je n'ai pas essayé sous un autre OS.
Merci d'avance pour votre temps et vos réponses
Partager