Pregunta

Dada una instancia x de Callable<T>, ¿cómo puedo ejecutar Process en un proceso separado de modo que pueda redirigir la entrada y salida estándar del proceso? Por ejemplo, ¿hay alguna manera de construir un Callable a partir de un Executor? ¿Existe un estándar <=> que da control sobre la entrada y la salida?

[ACTUALIZACIÓN] No es importante que el <=> se ejecute en un nuevo proceso en lugar de un nuevo hilo. Lo que quiero es poner la instancia <=> en un & Quot; arnés & Quot ;, para que pueda controlar su stdin / stdout. AFAIK, esto requiere un nuevo proceso.

¿Fue útil?

Solución

Más generalmente:

  

Dada una instancia x de invocable utilizando variables globales A y B, ¿cómo puedo ejecutar x simultáneamente para que x vea valores personalizados para A y B, en lugar de " original " valores de A y B?

Y la mejor respuesta es, no use variables globales. La dependencia inyecta cosas así. Extienda Callable y agregue métodos setStdIn, setStdOut (y setStdErr si lo necesita).

Sé que esta no es la respuesta que está buscando, pero las soluciones que he visto para todo esto requieren un nuevo proceso, y la única forma de obtener ese Llamable en un nuevo proceso es cambiar el código de Callable para que sea serializable, o proporcione un nombre de clase, o algún otro truco, por lo que en lugar de hacer cambios que le brinden una solución desagradable y frágil, simplemente hágalo bien *

* " derecha " ser usar el patrón ampliamente aceptado de inyección de dependencia para proporcionar un acoplamiento flojo. YMMV

ACTUALIZACIÓN: en respuesta al comentario 1. Aquí está su nueva interfaz:

import java.io.InputStream;
import java.io.PrintStream;
import java.util.concurrent.Callable;


public interface MyCallable<V> extends Callable<V> {
  void setStdIn(InputStream in);
  void setStdOut(PrintStream out);  
}

y sus tareas se verían así:

import java.io.InputStream;
import java.io.PrintStream;


public class CallableTask implements MyCallable<Object> {

    private InputStream in = System.in;
    private PrintStream out = System.out;

    public void setStdIn(InputStream in) {
        this.in = in;
    }

    public void setStdOut(PrintStream out) {
        this.out = out;
    }

    public Object call() throws Exception {
        out.write(in.read());
        return null;
    }

}

No es necesario un proceso. Es casi seguro que cualquier solución (incluso una que use procesos) requerirá cambios en el código de Callables de alguna manera. Este es el más simple (simplemente reemplace System.out con this.out).

Otros consejos

stdin / stdout se puede redirigir para todo el sistema, pero no estoy seguro de que se pueda redirigir para un solo subproceso: siempre se obtiene del sistema. (Sin embargo, puede hacer que System.out vaya a otra secuencia, lo he usado para capturar los seguimientos de la pila antes de que hubiera un método para obtener el seguimiento como una cadena)

Puede redirigir stdin / stdout, ejecutar el invocable y luego redirigirlo de nuevo, pero si algo más usa System.out mientras está redirigido, eso también irá a su nuevo archivo.

Los métodos serían System.setIn () y System.setOut () (y System.setErr ()) si desea seguir esa ruta.

Esfuércese por estructurar su código usando Parametrización desde arriba, Inyección de dependencias o como quiera llamarlo. Evite la estática, incluso aquellos disfrazados de solteros o escondidos en una biblioteca mala.

Si no quieres eliminar el uso de System.in/out/err estás de suerte. Estos se pueden configurar globalmente con System.set(In/Out/Err). Para poder transmitir de manera diferente para subprocesos individuales, configure una implementación que use ThreadLocal para encontrar un destino para delegar. Los locales de hilos son generalmente malvados, pero pueden ser útiles en situaciones desafortunadas.

De las aclaraciones, parece que el póster original no tiene necesidad de crear un proceso separado.

Eche un vistazo a la clase ProcessBuilder, le da la opción de capturar el stdout y stderr del proceso que se inicia.

Puede crear una clase Main que ejecute un invocable y luego ejecutarlo como otro jvm con un ProcessBuilder. La clase Main puede aceptar el nombre de su clase invocable como parámetro de entrada de línea de comando y cargarlo con Class.forName () y Class.newInstance ().

Una alternativa, si desea que ejecute una instancia invocable específica, es serializar la instancia en un archivo antes de iniciar el otro proceso (sería una forma muy cruda de comunicación entre los dos procesos).

La pregunta es, ¿por qué quieres hacerlo? ¿No puedes simplemente ejecutar tu invocable en otro hilo? java.util.concurrent tiene algunos grupos de subprocesos útiles, solo por eso.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top