¿Aplica un tiempo de espera en call-process / shell-command?

7

En algunos casos, al delegar el trabajo a un proceso externo, es útil establecer un tiempo de espera en el comando para evitar que Emacs se cuelgue indefinidamente.
Desafortunadamente, lo siguiente no funciona.

(with-timeout (1 nil)
  (call-process "/usr/bin/bash" nil t nil "-c" "sleep 10"))

Lo mismo vale para shell-command.

¿Hay alguna manera de establecer un tiempo de espera en estos procesos sincrónicos?
Es decir, quiero que el proceso se elimine automáticamente si no termina en un cierto número de segundos. ¿Es eso posible?

Malabarba
fuente
Nunca he usado with-timeout, pero he usado kill-processy delete-process.
ley
No estoy seguro, pero tal vez aceptar la salida del proceso ayudaría. Es decir, le diría a Emacs que tome la iniciativa y ejecute algún código de Elisp, supuestamente esperando que el proceso produzca algún resultado, tal vez, ese también sería un buen momento para matar el proceso si se agota el tiempo de espera.
wvxvw
@wvxvw Lo call-processanterior está configurando la salida para que se imprima en el búfer actual (obtengo el mismo efecto si paso un búfer de salida diferente). ¿Es eso lo que quieres decir?
Malabarba
No, lo siento, confundí algunas cosas. Quise decir esto: gnu.org/software/emacs/manual/html_node/elisp/… pero esto solo es relevante para los procesos asíncronos. Cuando esté en casa, buscaré en las call-processfuentes, pero ahora empiezo a sospechar que no hay forma de matarlo cuando se agota el tiempo.
wvxvw
En realidad, traté de buscarlo en Github: github.com/emacs-mirror/emacs/blob/… y, no, no veo ningún código que haga algo como establecer un tiempo de espera para el proceso.
wvxvw

Respuestas:

4

Mientras se call-processestá ejecutando, emacs procesará eventos, with-timeoutno funcionará sin esto:

El tiempo de espera se verifica cada vez que Emacs espera algún tipo de evento externo (como entrada de teclado, entrada de subprocesos o cierto tiempo); Si el programa se repite sin esperar de ninguna manera, no se detectará el tiempo de espera.

Todavía puede usar with-timeoutcon procesos (semi) sincrónicos.

Realmente usará un proceso asincrónico pero esperará sincrónicamente mientras se está ejecutando, Emacs procesará los eventos cuando ejecute sit-for, que puede ejecutar durante 0 segundos. Luego puede usar el argumento timeout-forms de with-timeoutpara matar el proceso si todavía se está ejecutando cuando se activa el tiempo de espera.

(with-current-buffer (get-buffer-create "*my-proc-buffer*")
  (let ((proc (start-process "myproc" (current-buffer) "bash" "-c" "sleep 4"))) ;; start an async process
    (with-timeout (2 (kill-process proc)) ;; on timeout, kill the process
      (while (process-live-p proc) ;; while process is running
        (sit-for .05)) ;; let emacs read events and run timmers (and check for timeout)
      (message "finished on time!!")))) ;; this will run only if there is no timeout
Jordon Biondo
fuente
Estoy teniendo un pequeño problema con esto. No se garantiza que la salida del proceso esté en el búfer de salida después de que finalice el ciclo. Estoy trabajando en eso llamando a otro (sit-for 0.2)después del whileciclo, pero eso se siente inestable. ¿Hay alguna manera de saber que la salida se ha impreso en el búfer?
Malabarba
No estoy seguro de eso. Sin embargo, supongo que si alcanza el tiempo de espera, el proceso no se realiza de todos modos, por lo que la salida no es relevante. ¿Qué haces para que la salida sea necesaria incluso después de un tiempo de espera? Potencialmente, podría cambiar a usar un filtro de proceso y matar el proceso solo pasaron X segundos sin salida en lugar de después de X segundos sin importar qué.
Jordon Biondo
Lo siento, no estaba claro. No me importa la salida cuando se alcanza el tiempo de espera. Estoy diciendo que la salida no se imprime inmediatamente después de que el proceso finalice con éxito .
Malabarba
Creo que el problema es que (sit-for 0)emacs pasa demasiado tiempo dejando que se ejecute el proceso y no escuchando suficientes eventos e insertando el texto en el búfer. Cuando cambio el mío a (sit-for .05)cosas, las cosas funcionan mejor y todo el texto entra en mi búfer. Incluso para un proceso corto .05 segundos no es una sobrecarga preocupante.
Jordon Biondo
No estoy demasiado preocupado por los gastos generales en esta situación. El proceso se llama 5-8 veces y todo es una operación interactiva que ya lleva al menos varios segundos, por lo que 1 segundo más no hará mucha diferencia. Lo que me preocupa un poco es la estabilidad, porque tuve que usar (sit-for 0.2)para que pasaran mis pruebas locales, y aun así, una vez que presioné los cambios, las pruebas de travis fallaron.
Malabarba
4

Puede lograr esto simplemente agregando una invocación de tiempo de espera de GNU a su comando de shell, lo que evita la necesidad de conocer cualquier detalle sobre el comportamiento de Emacs. Por ejemplo ejecutando:

$ timeout 5 sleep 10

Regresará en 5 segundos, no en 10 (el tiempo de espera efectivamente presiona Ctrl-C para usted).

Joseph Garvin
fuente
Gracias, puede que tenga que ir con esta opción si no puedo lograr la estabilidad con la otra. Sin embargo, hubiera preferido no confiar en otra utilidad, por lo que también funcionaría en Windows.
Malabarba