OVH Cloud OVH Cloud

Processes avec PythonWin et WinCVS

4 réponses
Avatar
Bernard Grosperrin
Bonjour tout le monde,

Pour un debutant en python, je me trouve confronte a un probleme sans doute
trop difficile pour moi....

D'abord, le contexte: je suis dans une macro ecrite pour WinCVS. Depuis
cette macro, je lance ( avec win32api.ShellExecute ) un executable
exterieur. J'ai besoin d'attendre que cette tache se termine avant de
rendre la main a l'utilisateur, ou passer a la tache suivante.

J'ai quelque chose qui fonctionnes, mais ce n'est pas tres elegant, dans la
mesure ou, des que je lance la macro, j'ai le curseur sablier, rien n'est
affiche dans la console, et tout s'affiche a la fin de la tache. Aussi,
avec le code qui suit, j'obtiens sytematiquement "Process Timed out", et il
semble que l'attente est directement fonction de ma variable timeout, comme
si la tache en question devenait dependante de ce code, et ne pouvait plus
se terminer par elle-meme. (sans ce code, la tache se termine en moins
d'une seconde).

Voici le code en question:

def WaitForProcess():
#time.sleep(0.5)
timeout = 1500
handles = []
pids = win32pdhutil.FindPerformanceAttributesByName("BG_DDE_CVS")
for pid in pids:
handle = win32api.OpenProcess(win32con.PROCESS_ALL_ACCESS, 1,pid)
handles.append(handle)

for handle in handles:
while 1:
result = win32event.WaitForSingleObject(handle, timeout)
if result == win32event.WAIT_OBJECT_0:
#print "Process terminated"
break
elif result == win32event.WAIT_TIMEOUT:
#print "Process Timed out"
break

si je lancais la tache avec CreateProcess, est-ce que cela me permettrait
de mieux la controler? Tout ce que je souhaites, c'est de savoir quand
cette tache se termine, sans pour autant bloquer l'interaction avec
l'utilisateur par la console.

Dans la cas qui me preocccupe pour l'instant, je n'ai qu'une seule tache
active. Je vais aussi devoir traiter le cas ou la meme tache est lancee
plusieurs fois en rafale, et attendre/savoir lorsque toutes les taches ont
termine leur job.

merci d'avance de vos conseils eclaires,
Bernard

4 réponses

Avatar
Bruno Desthuilliers
Bonjour tout le monde,

Pour un debutant en python, je me trouve confronte a un probleme sans doute
trop difficile pour moi....

D'abord, le contexte: je suis dans une macro ecrite pour WinCVS. Depuis
cette macro, je lance ( avec win32api.ShellExecute ) un executable
exterieur. J'ai besoin d'attendre que cette tache se termine avant de
rendre la main a l'utilisateur, ou passer a la tache suivante.

J'ai quelque chose qui fonctionnes, mais ce n'est pas tres elegant, dans la
mesure ou, des que je lance la macro, j'ai le curseur sablier, rien n'est
affiche dans la console, et tout s'affiche a la fin de la tache. Aussi,
avec le code qui suit, j'obtiens sytematiquement "Process Timed out", et il
semble que l'attente est directement fonction de ma variable timeout, comme
si la tache en question devenait dependante de ce code, et ne pouvait plus
se terminer par elle-meme. (sans ce code, la tache se termine en moins
d'une seconde).


Pour ce qui est des spécificités de l'api win32, je te renvoie vers un
ng approprié (fr.comp.os.ms-windows.programmation, au hasard...).
<hs>
Il me semble effectivement (de mémoire, et ça fait quelques années que
je n'ai pas mis le nez dans windows...) que createProcess() serait plus
approprié, mais vérifie quand même chez ceux qui savent.
</hs>

Quelques remarques sur la partie Python :

Voici le code en question:

def WaitForProcess():
#time.sleep(0.5)
timeout = 1500
handles = []
pids = win32pdhutil.FindPerformanceAttributesByName("BG_DDE_CVS")
for pid in pids:
handle = win32api.OpenProcess(win32con.PROCESS_ALL_ACCESS, 1,pid)
handles.append(handle)

for handle in handles:
while 1:
result = win32event.WaitForSingleObject(handle, timeout)
if result == win32event.WAIT_OBJECT_0:
#print "Process terminated"
break
elif result == win32event.WAIT_TIMEOUT:
#print "Process Timed out"
break


Avec cette boucle, tu prends un handle, et tu boucle tant que le process
n'est pas terminé *ou* time-out, puis tu passe au process suivant...
Si tu a un timeout, c'est que le temps que tu a fixé est passé. Tu te
retrouve donc, si ma logique est bonne, avec le risque de sortir de la
boucle avant que tous les process ne soient terminés.

ne vaudrait-il mieux pas faire l'inverse:

while handles:
handle = handles.pop()
result = win32event.WaitForSingleObject(handle, timeout)
if result == win32event.WAIT_TIMEOUT:
# c'est la fonction qui 'time-out', pas le process...
print "Timed out for %s" % handle
# si on a un time-out, c'est que le process n'est pas fini,
# donc on le rempile pour le prochain tour
handles.push(handle)
elif result == win32event.WAIT_OBJECT_0:
print "Process terminated, handle : %s" % handle
# pas besoin de break, il suffit de ne pas
# rempiler le handle
else:
# on a probablement un WAIT_FAIL,
# il serait bon de controler...
print "oops, je devrais penser à gerer tous les cas..."

Ceci étant, vu ce que fait la boucle, tu devrais regarder du côté de
WaitForMultipleObject()

si je lancais la tache avec CreateProcess, est-ce que cela me permettrait
de mieux la controler?


cf plus haut

Tout ce que je souhaites, c'est de savoir quand
cette tache se termine, sans pour autant bloquer l'interaction avec
l'utilisateur par la console.


Ta boucle ne rend pas la main de toutes façons. Tu a songé à la lancer
dans un thread ?-) Si c'est possible et si ça a un sens dans le cadre
que tu décris, bien sûr (macro...)


HTH
Bruno

Avatar
Bruno Desthuilliers

while handles:
handle = handles.pop()
result = win32event.WaitForSingleObject(handle, timeout)
if result == win32event.WAIT_TIMEOUT:
# c'est la fonction qui 'time-out', pas le process...
print "Timed out for %s" % handle
# si on a un time-out, c'est que le process n'est pas fini,
# donc on le rempile pour le prochain tour
handles.push(handle)
Il fallait lire

handles.insert(0, handle)
bien sûr...

Bruno

Avatar
F. Petitjean
Bonjour tout le monde,

Pour un debutant en python, je me trouve confronte a un probleme sans doute
trop difficile pour moi....

D'abord, le contexte: je suis dans une macro ecrite pour WinCVS. Depuis
cette macro, je lance ( avec win32api.ShellExecute ) un executable
exterieur. J'ai besoin d'attendre que cette tache se termine avant de
rendre la main a l'utilisateur, ou passer a la tache suivante.

J'ai quelque chose qui fonctionnes, mais ce n'est pas tres elegant, dans la
mesure ou, des que je lance la macro, j'ai le curseur sablier, rien n'est
affiche dans la console, et tout s'affiche a la fin de la tache. Aussi,
avec le code qui suit, j'obtiens sytematiquement "Process Timed out", et il
semble que l'attente est directement fonction de ma variable timeout, comme
si la tache en question devenait dependante de ce code, et ne pouvait plus
se terminer par elle-meme. (sans ce code, la tache se termine en moins
d'une seconde).

Voici le code en question:

def WaitForProcess():
(plein de windowseries incompréhensibles)


si je lancais la tache avec CreateProcess, est-ce que cela me permettrait
de mieux la controler? Tout ce que je souhaites, c'est de savoir quand
cette tache se termine, sans pour autant bloquer l'interaction avec
l'utilisateur par la console.
Si vous avez un python à jour (2.4) :

import subprocess
et comme la majeure partie est en python (même avec win32) vous regardez
comment c'est fait : il y a le CreateProcess quii va bien et
l'utilisation d'un fil d'exécution (thread) et WaitForJenePasQuoi.

à la base c'est

from subprocess import Popen
child = Popen(args, executable='xxxx.exe', ...)
Pour savoir si l'exécutable n'a pas terminé :
rc = child.poll()
pas_fini = rc is None
et si vous voulez bloquer l'interaction jusqu'à la fin
rc = child.wait()

Vous pouvez combiner cela avec un peu de threadind pour écrire
class Controller(threading.Thread):
"""
`Controller` class see c.l.py postings controls the end of a job
"""
(source d'un module Runner pour gérer tout cela disponible sur demande)
Dans la cas qui me preocccupe pour l'instant, je n'ai qu'une seule tache
active. Je vais aussi devoir traiter le cas ou la meme tache est lancee
plusieurs fois en rafale, et attendre/savoir lorsque toutes les taches ont
termine leur job.

merci d'avance de vos conseils eclaires,
Bernard


Avatar
Do Re Mi chel La Si Do
Bonsoir !

Subprocess existe aussi, comme module externe, pour Python 2.3 (chez Effbot,
si je me souviens bien).

@-salutations
--
Michel Claveau