Attendre la fin de l'exécution d'un processus asynchrone
13 réponses
Julien Gilli
Bonsoir,
J'essaie, en utilisant emacs lisp et emacs 21, d'exécuter un processus
asynchrone et d'attendre jusqu'à sa terminaison pour récupérer sa sortie
complète.
Pour cela, j'essaie d'utiliser une "sentinele" avec
set-process-sentinel, et une variable globale qui me permet de
déterminer quand l'exécution du processus s'est terminée.
La fonction x509-decode-cert prend un certificat au format PEM en entree
(une chaine de caracteres) et renvoie une chaine contenant la sortie de
l'execution de la commande openssl permettant de décoder ce certificat
pour rendre son contenu lisible facilement.
Le comportement que j'obtiens n'est pas celui que j'attends. Il
semblerait que la variable "process-termination-flag" ne soit jamais
modifée, alors que l'évenement "finished" est bien reçu par la
sentinelle : lorsque je presse ctrl-g, le message "finished" apparait
bien dans le mini-buffer.
Si je ne prends pas garde à ce que le processus soit terminé avant de
renvoyer sa sortie, j'obtiens la sortie complète, et je pourrais
considérer que mon code fonctionne. Cependant, le code ne me parait pas
être assez robuste sans utiliser de sentinelle : il serait possible de
renvoyer la sortie partielle du processus avant que ce dernier ne soit
terminé.
Quelle est la bonne façon de récupérer _toute_ la sortie d'une processus
exécuté de manière asynchrone de manière robuste ? Il semblerait que
Xemacs propose une fonction intégrée "process-live-p" qui détermine si
un processus est toujours en cours d'exécution, est-ce qu'une telle
fonctionnalité existe pour Emacs ?
L'emacs-lisp n'est pas préemptif ! Avec une boucle comme celle là, tu as une boucle infinie ...
Si tu tiens à faire une boucle d'attente de ce style, C-h f sit-for RET, mais ça me semble être une drôle de façon de faire : Si tu veux que ton code s'arrête et reprenne quand le processus est terminé, c'est un processus synchrone qu'il te faut. Sinon, met le code que tu aurais mis à la fin de ta fonction dans la sentinelle.
L'emacs-lisp n'est pas préemptif ! Avec une boucle comme celle là, tu
as une boucle infinie ...
Si tu tiens à faire une boucle d'attente de ce style, C-h f sit-for RET,
mais ça me semble être une drôle de façon de faire : Si tu veux que
ton code s'arrête et reprenne quand le processus est terminé, c'est un
processus synchrone qu'il te faut. Sinon, met le code que tu aurais
mis à la fin de ta fonction dans la sentinelle.
L'emacs-lisp n'est pas préemptif ! Avec une boucle comme celle là, tu as une boucle infinie ...
Si tu tiens à faire une boucle d'attente de ce style, C-h f sit-for RET, mais ça me semble être une drôle de façon de faire : Si tu veux que ton code s'arrête et reprenne quand le processus est terminé, c'est un processus synchrone qu'il te faut. Sinon, met le code que tu aurais mis à la fin de ta fonction dans la sentinelle.
C'est à dire ? Il ne permet pas la programmation concurrente ? Ou bien Emacs ne préempte pas les tâches s'exécutant de manière concurrente et c'est au code s'exécutant dans la boucle while de rendre volontairement la main périodiquement à emacs pour que la sentinelle puisse paramétrer le bon flag ?
Si tu tiens à faire une boucle d'attente de ce style, C-h f sit-for RET, mais ça me semble être une drôle de façon de faire : Si tu veux que ton code s'arrête et reprenne quand le processus est terminé, c'est un processus synchrone qu'il te faut.
Apparemment, toutes les fonctions exécutant un processus de manière synchrone ne permettent pas d'envoyer des données dans l'entrée standard d'une processus. Il faudrait alors créer un fichier temporaire, exécuter le processus de manière synchrone et enfin supprimer le fichier temporaire. Si c'est possible, je préfère ne pas créer de fichier temporaire.
Sinon, met le code que tu aurais mis à la fin de ta fonction dans la sentinelle.
Est-ce que cela signifie que le code de sentinelle est exécuté de manière synchrone à un instant précis ? Je pensais qu'une sentinelle était appellée de manière asynchrone à chaque fois qu'un processus recevait un évenement particulier. Si c'était le cas, positionner un flag dans le code de la sentinelle ou y exécuter le code qui est censé l'être lorsqu'un flag est positionné devrait être équivalent.
C'est à dire ? Il ne permet pas la programmation concurrente ? Ou bien
Emacs ne préempte pas les tâches s'exécutant de manière concurrente et
c'est au code s'exécutant dans la boucle while de rendre volontairement
la main périodiquement à emacs pour que la sentinelle puisse paramétrer
le bon flag ?
Si tu tiens à faire une boucle d'attente de ce style, C-h f sit-for RET,
mais ça me semble être une drôle de façon de faire : Si tu veux que
ton code s'arrête et reprenne quand le processus est terminé, c'est un
processus synchrone qu'il te faut.
Apparemment, toutes les fonctions exécutant un processus de manière
synchrone ne permettent pas d'envoyer des données dans l'entrée standard
d'une processus. Il faudrait alors créer un fichier temporaire, exécuter
le processus de manière synchrone et enfin supprimer le fichier
temporaire. Si c'est possible, je préfère ne pas créer de fichier
temporaire.
Sinon, met le code que tu aurais
mis à la fin de ta fonction dans la sentinelle.
Est-ce que cela signifie que le code de sentinelle est exécuté de
manière synchrone à un instant précis ? Je pensais qu'une sentinelle
était appellée de manière asynchrone à chaque fois qu'un processus
recevait un évenement particulier. Si c'était le cas, positionner un
flag dans le code de la sentinelle ou y exécuter le code qui est censé
l'être lorsqu'un flag est positionné devrait être équivalent.
C'est à dire ? Il ne permet pas la programmation concurrente ? Ou bien Emacs ne préempte pas les tâches s'exécutant de manière concurrente et c'est au code s'exécutant dans la boucle while de rendre volontairement la main périodiquement à emacs pour que la sentinelle puisse paramétrer le bon flag ?
Si tu tiens à faire une boucle d'attente de ce style, C-h f sit-for RET, mais ça me semble être une drôle de façon de faire : Si tu veux que ton code s'arrête et reprenne quand le processus est terminé, c'est un processus synchrone qu'il te faut.
Apparemment, toutes les fonctions exécutant un processus de manière synchrone ne permettent pas d'envoyer des données dans l'entrée standard d'une processus. Il faudrait alors créer un fichier temporaire, exécuter le processus de manière synchrone et enfin supprimer le fichier temporaire. Si c'est possible, je préfère ne pas créer de fichier temporaire.
Sinon, met le code que tu aurais mis à la fin de ta fonction dans la sentinelle.
Est-ce que cela signifie que le code de sentinelle est exécuté de manière synchrone à un instant précis ? Je pensais qu'une sentinelle était appellée de manière asynchrone à chaque fois qu'un processus recevait un évenement particulier. Si c'était le cas, positionner un flag dans le code de la sentinelle ou y exécuter le code qui est censé l'être lorsqu'un flag est positionné devrait être équivalent.
Merci pour votre attention !
-- Julien Gilli
Matthieu Moy
Julien Gilli writes:
L'emacs-lisp n'est pas préemptif !
C'est à dire ? Il ne permet pas la programmation concurrente ?
Tu ne peux pas faire grand chose au niveau programmation concurrente: Il n'y a pas de parallelisme réel. Une tache ne peut commencer à s'executer que quand la précédante a terminé.
Ou bien Emacs ne préempte pas les tâches s'exécutant de manière concurrente et c'est au code s'exécutant dans la boucle while de rendre volontairement la main périodiquement à emacs pour que la sentinelle puisse paramétrer le bon flag ?
Tout à fait. Cf. sit-for.
Apparemment, toutes les fonctions exécutant un processus de manière synchrone ne permettent pas d'envoyer des données dans l'entrée standard d'une processus.
Ça parait relativement logique : Emacs se bloque en attendant la fin du processus, donc il ne peut rien faire en attendant.
Sinon, met le code que tu aurais mis à la fin de ta fonction dans la sentinelle.
Est-ce que cela signifie que le code de sentinelle est exécuté de manière synchrone à un instant précis ?
Qu'entends-tu par « synchrone » ou « asynchrone » dans ce contexte ? En générale, quand on dit « asynchrone » pour ce genre de choses, c'est pour dire « retourne à l'appelant avant d'avoir terminé », mais là l'appelant, c'est Emacs (pas ton code) et on s'en fout un peu ...
Je pensais qu'une sentinelle était appellée de manière asynchrone à chaque fois qu'un processus recevait un évenement particulier. Si c'était le cas, positionner un flag dans le code de la sentinelle ou y exécuter le code qui est censé l'être lorsqu'un flag est positionné devrait être équivalent.
Si tu met le code dans la sentinelle, il sera executé quand le processus termine, mais rien en attendant. Si tu fais une boucle d'attente, ton Emacs continue de faire des choses en attendant, c'est beaucoup moins efficace.
Regardes le nombre de processus qui tournent sur ta machine (sur la mienne, au moment ou je parle, il y en a 94) et le nombre de processus vraiment actifs en moyenne (0.1 sur ma machine au moment ou je parle). Imagine ce qu'il se passerait si les 93 processus en attente passive faisaient un "while (!event) {};" à la place ...
-- Matthieu
Julien Gilli <julien.gilli@gmail.com> writes:
L'emacs-lisp n'est pas préemptif !
C'est à dire ? Il ne permet pas la programmation concurrente ?
Tu ne peux pas faire grand chose au niveau programmation concurrente:
Il n'y a pas de parallelisme réel. Une tache ne peut commencer à
s'executer que quand la précédante a terminé.
Ou bien Emacs ne préempte pas les tâches s'exécutant de manière
concurrente et c'est au code s'exécutant dans la boucle while de
rendre volontairement la main périodiquement à emacs pour que la
sentinelle puisse paramétrer le bon flag ?
Tout à fait. Cf. sit-for.
Apparemment, toutes les fonctions exécutant un processus de manière
synchrone ne permettent pas d'envoyer des données dans l'entrée standard
d'une processus.
Ça parait relativement logique : Emacs se bloque en attendant la fin
du processus, donc il ne peut rien faire en attendant.
Sinon, met le code que tu aurais
mis à la fin de ta fonction dans la sentinelle.
Est-ce que cela signifie que le code de sentinelle est exécuté de
manière synchrone à un instant précis ?
Qu'entends-tu par « synchrone » ou « asynchrone » dans ce contexte ?
En générale, quand on dit « asynchrone » pour ce genre de choses,
c'est pour dire « retourne à l'appelant avant d'avoir terminé », mais
là l'appelant, c'est Emacs (pas ton code) et on s'en fout un peu ...
Je pensais qu'une sentinelle était appellée de manière asynchrone à
chaque fois qu'un processus recevait un évenement particulier. Si
c'était le cas, positionner un flag dans le code de la sentinelle ou
y exécuter le code qui est censé l'être lorsqu'un flag est
positionné devrait être équivalent.
Si tu met le code dans la sentinelle, il sera executé quand le
processus termine, mais rien en attendant. Si tu fais une boucle
d'attente, ton Emacs continue de faire des choses en attendant, c'est
beaucoup moins efficace.
Regardes le nombre de processus qui tournent sur ta machine (sur la
mienne, au moment ou je parle, il y en a 94) et le nombre de processus
vraiment actifs en moyenne (0.1 sur ma machine au moment ou je parle).
Imagine ce qu'il se passerait si les 93 processus en attente passive
faisaient un "while (!event) {};" à la place ...
C'est à dire ? Il ne permet pas la programmation concurrente ?
Tu ne peux pas faire grand chose au niveau programmation concurrente: Il n'y a pas de parallelisme réel. Une tache ne peut commencer à s'executer que quand la précédante a terminé.
Ou bien Emacs ne préempte pas les tâches s'exécutant de manière concurrente et c'est au code s'exécutant dans la boucle while de rendre volontairement la main périodiquement à emacs pour que la sentinelle puisse paramétrer le bon flag ?
Tout à fait. Cf. sit-for.
Apparemment, toutes les fonctions exécutant un processus de manière synchrone ne permettent pas d'envoyer des données dans l'entrée standard d'une processus.
Ça parait relativement logique : Emacs se bloque en attendant la fin du processus, donc il ne peut rien faire en attendant.
Sinon, met le code que tu aurais mis à la fin de ta fonction dans la sentinelle.
Est-ce que cela signifie que le code de sentinelle est exécuté de manière synchrone à un instant précis ?
Qu'entends-tu par « synchrone » ou « asynchrone » dans ce contexte ? En générale, quand on dit « asynchrone » pour ce genre de choses, c'est pour dire « retourne à l'appelant avant d'avoir terminé », mais là l'appelant, c'est Emacs (pas ton code) et on s'en fout un peu ...
Je pensais qu'une sentinelle était appellée de manière asynchrone à chaque fois qu'un processus recevait un évenement particulier. Si c'était le cas, positionner un flag dans le code de la sentinelle ou y exécuter le code qui est censé l'être lorsqu'un flag est positionné devrait être équivalent.
Si tu met le code dans la sentinelle, il sera executé quand le processus termine, mais rien en attendant. Si tu fais une boucle d'attente, ton Emacs continue de faire des choses en attendant, c'est beaucoup moins efficace.
Regardes le nombre de processus qui tournent sur ta machine (sur la mienne, au moment ou je parle, il y en a 94) et le nombre de processus vraiment actifs en moyenne (0.1 sur ma machine au moment ou je parle). Imagine ce qu'il se passerait si les 93 processus en attente passive faisaient un "while (!event) {};" à la place ...
-- Matthieu
Matthieu Moy
Julien Gilli writes:
Si tu met le code dans la sentinelle, il sera executé quand le processus termine, mais rien en attendant.
Ce qui signifie que Emacs est tout de même capable de préempter mon code, non ?
Non. La tâche « sentinelle » devient éligible quand ton processus termine. Elle est executée quand la tâche en cours termine (enfin, plus exactement, quand son tour vient dans la file des tâches éligibles).
Si tu fais une boucle d'attente, ton Emacs continue de faire des choses en attendant, c'est beaucoup moins efficace.
Oui, j'en conviens, j'essaie juste de comprendre comment utiliser les outils mis à ma disposition par Emacs pour écrire un code robuste.
Mais ou est le problème en utilisant la sentinelle directement ?
-- Matthieu
Julien Gilli <julien.gilli@gmail.com> writes:
Si tu met le code dans la sentinelle, il sera executé quand le
processus termine, mais rien en attendant.
Ce qui signifie que Emacs est tout de même capable de préempter mon
code, non ?
Non. La tâche « sentinelle » devient éligible quand ton processus
termine. Elle est executée quand la tâche en cours termine (enfin,
plus exactement, quand son tour vient dans la file des tâches
éligibles).
Si tu fais une boucle
d'attente, ton Emacs continue de faire des choses en attendant, c'est
beaucoup moins efficace.
Oui, j'en conviens, j'essaie juste de comprendre comment utiliser les
outils mis à ma disposition par Emacs pour écrire un code robuste.
Mais ou est le problème en utilisant la sentinelle directement ?
Si tu met le code dans la sentinelle, il sera executé quand le processus termine, mais rien en attendant.
Ce qui signifie que Emacs est tout de même capable de préempter mon code, non ?
Non. La tâche « sentinelle » devient éligible quand ton processus termine. Elle est executée quand la tâche en cours termine (enfin, plus exactement, quand son tour vient dans la file des tâches éligibles).
Si tu fais une boucle d'attente, ton Emacs continue de faire des choses en attendant, c'est beaucoup moins efficace.
Oui, j'en conviens, j'essaie juste de comprendre comment utiliser les outils mis à ma disposition par Emacs pour écrire un code robuste.
Mais ou est le problème en utilisant la sentinelle directement ?
-- Matthieu
Matthieu Moy
Julien Gilli writes:
Matthieu Moy wrote:
Julien Gilli writes:
Si tu met le code dans la sentinelle, il sera executé quand le processus termine, mais rien en attendant.
Ce qui signifie que Emacs est tout de même capable de préempter mon code, non ?
Non. La tâche « sentinelle » devient éligible quand ton processus termine. Elle est executée quand la tâche en cours termine (enfin, plus exactement, quand son tour vient dans la file des tâches éligibles).
Apparemment, je ne spécifie nulle part dans mon code volontairement que je donne la main à Emacs pour exécuter le code de la fonction sentinelle.
Oui, mais justement, ça ne marche pas. Ta sentinelle n'est executée que quand tu fais un C-g, donc quand tu interromp la boucle active à la main, et un peu brutalement.
Qu'entendez vous par "utiliser la sentinelle directement" ?
Mettre le code à executer après la fin du processus directement dans la sentinelle.
-- Matthieu
Julien Gilli <julien.gilli@gmail.com> writes:
Matthieu Moy wrote:
Julien Gilli <julien.gilli@gmail.com> writes:
Si tu met le code dans la sentinelle, il sera executé quand le
processus termine, mais rien en attendant.
Ce qui signifie que Emacs est tout de même capable de préempter mon
code, non ?
Non. La tâche « sentinelle » devient éligible quand ton processus
termine. Elle est executée quand la tâche en cours termine (enfin,
plus exactement, quand son tour vient dans la file des tâches
éligibles).
Apparemment, je ne spécifie nulle part dans mon code volontairement que
je donne la main à Emacs pour exécuter le code de la fonction
sentinelle.
Oui, mais justement, ça ne marche pas. Ta sentinelle n'est executée
que quand tu fais un C-g, donc quand tu interromp la boucle active à
la main, et un peu brutalement.
http://www.tac.nyc.ny.us/manuals/elisp/elisp_484.html#SEC487
« A sentinel runs only while Emacs is waiting »
Qu'entendez vous par "utiliser la sentinelle directement" ?
Mettre le code à executer après la fin du processus directement dans
la sentinelle.
Si tu met le code dans la sentinelle, il sera executé quand le processus termine, mais rien en attendant.
Ce qui signifie que Emacs est tout de même capable de préempter mon code, non ?
Non. La tâche « sentinelle » devient éligible quand ton processus termine. Elle est executée quand la tâche en cours termine (enfin, plus exactement, quand son tour vient dans la file des tâches éligibles).
Apparemment, je ne spécifie nulle part dans mon code volontairement que je donne la main à Emacs pour exécuter le code de la fonction sentinelle.
Oui, mais justement, ça ne marche pas. Ta sentinelle n'est executée que quand tu fais un C-g, donc quand tu interromp la boucle active à la main, et un peu brutalement.
Qu'entendez vous par "utiliser la sentinelle directement" ?
Mettre le code à executer après la fin du processus directement dans la sentinelle.
-- Matthieu
drkm
Julien Gilli wrote:
J'essaie, en utilisant emacs lisp et emacs 21, d'exécuter un processus asynchrone et d'attendre jusqu'à sa terminaison pour récupérer sa s ortie complète.
Je n'ai pas réellement suivit en détail la discussion, mais pourquoi veux-tu utiliser un processus asynchrone dans ce cas ?
--drkm
Julien Gilli wrote:
J'essaie, en utilisant emacs lisp et emacs 21, d'exécuter un processus
asynchrone et d'attendre jusqu'à sa terminaison pour récupérer sa s ortie
complète.
Je n'ai pas réellement suivit en détail la discussion, mais
pourquoi veux-tu utiliser un processus asynchrone dans ce cas ?
J'essaie, en utilisant emacs lisp et emacs 21, d'exécuter un processus asynchrone et d'attendre jusqu'à sa terminaison pour récupérer sa s ortie complète.
Je n'ai pas réellement suivit en détail la discussion, mais pourquoi veux-tu utiliser un processus asynchrone dans ce cas ?
--drkm
Matthieu Moy
Julien Gilli writes:
Matthieu Moy wrote:
Julien Gilli writes:
Qu'entendez vous par "utiliser la sentinelle directement" ?
Mettre le code à executer après la fin du processus directement dans la sentinelle.
Dans ce cas, suis-je assuré du fait que le processus asynchrone soit terminé à la sortie de la fonction x509-decode-cert ?
Non :-(
J'ai enfin compris ton problème (je suis un peu long à la détente ;-) ).
En d'autres termes, existe-il un moyen pour etre assuré qu'avant l'exécution d'une certaine ligne de code, un processus crée de manière asynchrone soit terminé, sans effectuer de boucle active ?
La manière « standard » dans ce cas, c'est de passer un callback à `x509-decode-cert'. C'est un peu chiant, mais je ne connais pas de meilleur moyen.
-- Matthieu
Julien Gilli <julien.gilli@gmail.com> writes:
Matthieu Moy wrote:
Julien Gilli <julien.gilli@gmail.com> writes:
Qu'entendez vous par "utiliser la sentinelle directement" ?
Mettre le code à executer après la fin du processus directement dans
la sentinelle.
Dans ce cas, suis-je assuré du fait que le processus asynchrone soit
terminé à la sortie de la fonction x509-decode-cert ?
Non :-(
J'ai enfin compris ton problème (je suis un peu long à la détente ;-) ).
En d'autres termes, existe-il un moyen pour etre assuré qu'avant
l'exécution d'une certaine ligne de code, un processus crée de
manière asynchrone soit terminé, sans effectuer de boucle active ?
La manière « standard » dans ce cas, c'est de passer un callback à
`x509-decode-cert'. C'est un peu chiant, mais je ne connais pas de
meilleur moyen.
Qu'entendez vous par "utiliser la sentinelle directement" ?
Mettre le code à executer après la fin du processus directement dans la sentinelle.
Dans ce cas, suis-je assuré du fait que le processus asynchrone soit terminé à la sortie de la fonction x509-decode-cert ?
Non :-(
J'ai enfin compris ton problème (je suis un peu long à la détente ;-) ).
En d'autres termes, existe-il un moyen pour etre assuré qu'avant l'exécution d'une certaine ligne de code, un processus crée de manière asynchrone soit terminé, sans effectuer de boucle active ?
La manière « standard » dans ce cas, c'est de passer un callback à `x509-decode-cert'. C'est un peu chiant, mais je ne connais pas de meilleur moyen.
-- Matthieu
Julien Gilli
drkm wrote:
Julien Gilli wrote:
J'essaie, en utilisant emacs lisp et emacs 21, d'exécuter un processus asynchrone et d'attendre jusqu'à sa terminaison pour récupérer sa sortie complète.
Je n'ai pas réellement suivit en détail la discussion, mais pourquoi veux-tu utiliser un processus asynchrone dans ce cas ?
Parce qu'il semblerait que ce soit le seul moyen de pouvoir lui envoyer des données en entrée sans utiliser un fichier temporaire.
-- Julien Gilli
drkm wrote:
Julien Gilli wrote:
J'essaie, en utilisant emacs lisp et emacs 21, d'exécuter un processus
asynchrone et d'attendre jusqu'à sa terminaison pour récupérer sa sortie
complète.
Je n'ai pas réellement suivit en détail la discussion, mais
pourquoi veux-tu utiliser un processus asynchrone dans ce cas ?
Parce qu'il semblerait que ce soit le seul moyen de pouvoir lui envoyer
des données en entrée sans utiliser un fichier temporaire.
J'essaie, en utilisant emacs lisp et emacs 21, d'exécuter un processus asynchrone et d'attendre jusqu'à sa terminaison pour récupérer sa sortie complète.
Je n'ai pas réellement suivit en détail la discussion, mais pourquoi veux-tu utiliser un processus asynchrone dans ce cas ?
Parce qu'il semblerait que ce soit le seul moyen de pouvoir lui envoyer des données en entrée sans utiliser un fichier temporaire.
-- Julien Gilli
Matthieu Moy
Julien Gilli writes:
Je ne vois pas comment un callback pourrait résoudre mon problème. Pouvez vous détailler un peu plus votre idée s'il vous plaît ?