2010-05-16 7 views
7

Ho bisogno di avere uno streaming char bufferizzato, in cui scrivo in un thread e dal quale ho letto in un altro thread. Right now Sto utilizzando PipedReader e PipedWriter per esso, ma tali classi causare un problema di prestazioni: PipedReader fa un wait(1000) quando il suo buffer interno è vuoto, che causa la mia domanda di ritardo visibilmente.Migliore alternativa per PipedReader/PipedWriter?

Ci sarebbe qualche libreria che fa la stessa cosa come PipedReader/PipedWriter, ma con prestazioni migliori? O dovrò implementare le mie ruote?

+0

Questo potrebbe non essere quello che vuoi, ma il thread di scrittura sarebbe in grado di notificare il thread di lettura dopo aver scritto qualcosa? E il thread di lettura continuerà a leggere mentre 'ready()' è vero, quindi dormi quando non lo è? – Phil

+0

Puoi mostrarci il tuo codice, per favore?Il 'wait (1000)' non dovrebbe essere il problema, perché lo scrittore notifica al lettore quando qualcosa è scritto. Il lettore allora fugge dalla sua attesa(). – tangens

+0

Grazie, Phil. In questo momento non sono a casa, quindi non posso testarlo, ma basandomi sul codice sorgente, PipedWriter.flush() sembra notificare i lettori. Ci proverò più tardi oggi. –

risposta

5

Il problema è che quando qualcosa viene scritto nel PipedWriter, non notificare automaticamente la PipedReader che ci sono alcuni dati da leggere. Quando si tenta di leggere PipedReader e il buffer è vuoto, PipedReader eseguirà un ciclo e attenderà utilizzando una chiamata wait(1000) fino a quando il buffer non avrà alcuni dati.

La soluzione è quella di chiamare PipedWriter.flush() sempre dopo aver scritto qualcosa al tubo. Tutto ciò che fa il flush è chiamare notifyAll() sul lettore. La correzione del codice in questione looks like this.

(Per me l'implementazione di PipedReader/PipedWriter assomiglia molto a un caso di ottimizzazione prematura - perché non notificare All in ogni scrittura? Anche i lettori attendono in un ciclo attivo, svegliandosi ogni secondo, invece di svegliarsi solo quando è qualcosa da leggere. Il codice contiene anche alcuni commenti, che il rilevamento del thread reader/writer non è abbastanza sofisticato.)

Questo stesso problema sembra essere anche in PipedOutputStream. Nel mio attuale progetto chiamare flush() manualmente non è possibile (non è possibile modificare i Commons IO IOUtils.copy()), quindi l'ho risolto creando low-latency wrappers per le classi di pipe. Funzionano molto meglio delle classi originali. :-)

1

Dovrebbe essere abbastanza semplice racchiudere un'API del flusso di carbone intorno a BlockingQueue.

Devo dire, però, sembra abbastanza perverso che PipedReader userebbero polling per attendere i dati. È documentato da qualche parte o l'hai scoperto per te in qualche modo?

+0

Penso che volevi collegarti a "http://java.sun.com/javase/6/docs/api/java/util/concurrent/BlockingQueue.html" – Phil

+0

Sì, questo è il mio piano B, se non posso trova una classe che fa già ciò di cui ho bisogno. –

+0

Grazie Phil. Ero troppo veloce nel sorteggio con la mia ricerca su Google. :-) –

0

ho implementato qualcosa di un po 'simile, e asked a question se qualcun altro aveva di meglio congegnata e testati codice.

1

@Esko Luontola, ho letto il codice nel pacchetto sbt per cercare di capire cosa stai facendo. Sembra che tu voglia avviare uno Process e passare l'input ad esso, e avere il risultato dell'azione essere in punti diversi. È corretto?

vorrei provare a modificare il ciclo principale in ReaderToWriterCopier in modo che invece di fare un read() - un'operazione di blocco che, apparentemente, quando è coinvolto un PipedReader cause di polling - si attende esplicitamente la Writer-flush. La documentazione è chiara che lo flush causa la notifica di qualsiasi Reader s.

Non sono sicuro di come eseguire il codice in modo che non possa approfondire. Spero che questo ti aiuti.

+0

Il mio caso d'uso è che ci sono più lettori per ciò che un 'Processo' stampa, e ciascuno di quei lettori ha bisogno della propria copia del flusso, a partire dal momento attuale e termina quando il lettore è chiuso. Lettori diversi non si influenzano a vicenda. Quello che legge PipedReader è ad esempio 'OutputReader.waitForOutput()'. Lo scrittore è 'ReaderToWriterCopier'. Il programma principale è 'SbtRunner', e le fonti di test hanno' SbtRunnerTester' che lo usa. SBT sta per http://code.google.com/p/simple-build-tool/ –

Problemi correlati