Domanda

È possibile utilizzare NIO per elaborare lo stdout da un processo? Lo sto lavorando con java.io, ma questo è qualcosa di un esercizio per imparare qualcosa in più su NIO ed esplorare la possibilità di miglioramenti delle prestazioni.

Fondamentalmente voglio trasmettere un grande volume di testo da stdout a un buffer il più velocemente possibile senza bloccare, e quindi elaborare il contenuto di quel buffer in un secondo momento. Il problema è che non riesco a capire il voodoo giusto per farlo funzionare con NIO. Questo è dove sono adesso:

ProcessBuilder pb = new ProcessBuilder( ... );
Process p = pb.start();
stdout = new StreamConsumer(p.getInputStream());
new Thread(stdout).start();
// other stuff omitted for brevity

La classe StreamConsumer è simile alla seguente:

class StreamConsumer implements Runnable
{
  private InputStream is;

  public StreamConsumer(InputStream is)
  {
    this.is = is;
  }

  public void run()
  {
    try
    {
      ReadableByteChannel source = Channels.newChannel(is);

      // Is it possible get a channel to a ByteBuffer 
      // or MappedByteBuffer here?
      WritableByteChannel destination = ??;
      ByteBuffer buffer = ByteBuffer.allocateDirect(128 * 1024);

      while (source.read(buffer) != -1)
      {
        buffer.flip();
        while (buffer.hasRemaining())
        {
          destination.write(buffer);
        }
        buffer.clear();
      }

      source.close();
      destination.close();
    }
    catch (IOException e)
    {
      e.printStackTrace();
    }
  }
}
È stato utile?

Soluzione

Che ci crediate o no, penso che il canale di byte scrivibile che si desidera sia

ByteArrayOutputStream ostream = new ByteArrayOutputStream(<some large number>);
WritableByteChannel destination = Channels.newChannel(ostream);

Quindi quando fatto

ostream.toByteArray() 

contiene i byte da elaborare. Oppure, se si desidera un buffer di byte,

ByteBuffer.wrap(ostream.toByteArray())

Non vedo qui come ottenere l'output al di fuori del runnable, ma sospetto che il tuo codice originale lo avesse. Altrimenti potresti voler StreamConsumer essere Callable<ByteBuffer>.

Altri suggerimenti

Ho creato una libreria open source che consente I / O non bloccanti tra i processi java e child. La libreria fornisce un modello di callback basato sugli eventi. Dipende dalla libreria JNA per utilizzare API native specifiche della piattaforma, come epoll su Linux, kqueue / kevent su MacOS X o porte di completamento IO su Windows.

Il progetto si chiama NuProcess e può essere trovato qui:

https://github.com/brettwooldridge/NuProcess

  

potresti volere che StreamConsumer sia un callable.

Un'altra opzione non bloccante da provare potrebbe essere quella di utilizzare ListenableFuture di Guava per darti callback di successo e fallimento senza interpretare i tuoi errori.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top