2010-05-16 20 views
7

Necesito tener una secuencia de char con buffer, en la que escribo en un hilo y desde la que leo en otro hilo. Right now estoy usando PipedReader y PipedWriter para ello, pero esas clases causar un problema de rendimiento: PipedReader hace un wait(1000) cuando su memoria intermedia interna está vacía, lo que hace que mi solicitud a la zaga de forma visible.¿Mejor alternativa para PipedReader/PipedWriter?

¿Habría alguna biblioteca que haga lo mismo que PipedReader/PipedWriter, pero con un mejor rendimiento? ¿O tendré que implementar mis propias ruedas?

+0

Esto puede no ser lo que quieres, pero ¿podría tu hilo de escritura notificar el hilo de lectura después de haber escrito algo? Y el hilo de lectura seguirá leyendo mientras 'ready()' es verdadero, y luego dormirá cuando no lo esté? – Phil

+0

¿Podría mostrarnos su código, por favor?La 'espera (1000)' no debería ser el problema, porque el escritor notifica al lector cuando algo está escrito. El lector se escapa de su espera(). – tangens

+0

Gracias, Phil. Ahora mismo no estoy en casa, así que no puedo probarlo, pero basado en el código fuente PipedWriter.flush() parece notificar a los lectores. Lo intentaré más tarde hoy. –

Respuesta

5

El problema fue que cuando algo se escribe en el PipedWriter, no notifica automáticamente el PipedReader que hay algunos datos a leer. Cuando uno intenta leer PipedReader y el búfer está vacío, el PipedReader hará un bucle y esperará usando una llamada wait(1000) hasta que el búfer tenga algunos datos.

La solución es llamar al PipedWriter.flush() siempre después de escribir algo en la tubería. Todo lo que hace la descarga es llamar al notifyAll() en el lector. La solución al código en la pregunta looks like this.

(Para mí, la implementación PipedReader/PipedWriter se parece mucho a un caso de optimización prematura, ¿por qué no notificar todo en cada escritura? También los lectores esperan en un bucle activo, despertando cada segundo, en lugar de despertarse solo cuando es algo para leer. El código también contiene algunos comentarios pendientes, que la detección de hilos del lector/escritor que no es lo suficientemente sofisticada)

Este mismo problema parece estar también en PipedOutputStream. En mi proyecto actual, llamar al flush() manualmente no es posible (no puedo modificar Commons IO's IOUtils.copy()), así que lo solucioné creando low-latency wrappers para las clases de tuberías. Funcionan mucho mejor que las clases originales. :-)

1

Debería ser bastante fácil envolver una API de secuencia char alrededor de BlockingQueue.

Debo decir, sin embargo, parece bastante perverso que PipedReader usaría sondeo para esperar los datos. ¿Está documentado esto en alguna parte, o lo descubriste por ti mismo de alguna manera?

+0

Creo que quisiste vincular a "http://java.sun.com/javase/6/docs/api/java/util/concurrent/BlockingQueue.html" – Phil

+0

Sí, ese es mi plan B, si no puedo encuentra una clase que ya haga lo que necesito. –

+0

Gracias Phil. Fui demasiado rápido en el sorteo con mi búsqueda en Google. :-) –

0

he implementado algo un poco similar y asked a question si alguien más había nada mejor pensado y código de prueba.

1

@Esko Luontola, he estado leyendo su código en el paquete sbt para tratar de entender lo que está haciendo. Parece que desea iniciar un Process y pasarle una entrada, y hacer que el resultado de la acción llegue a diferentes lugares. ¿Es esto correcto?

Me gustaría probar la modificación del bucle principal en ReaderToWriterCopier de manera que en vez de hacer un read() - una operación de bloqueo que, al parecer cuando un PipedReader participa causa de votación - esperas explícitamente la Writer-flush. La documentación es clara que flush hace que cualquier Reader s sea notificado.

No estoy seguro de cómo ejecutar su código, así que no puedo profundizar en él. Espero que esto ayude.

+0

Mi caso de uso es que hay múltiples lectores para lo que un 'Proceso' imprime, y cada uno de esos lectores necesita su propia copia de la secuencia, comenzando desde el momento actual y terminando cuando el lector está cerrado. Diferentes lectores que no se afectan entre sí. El que lee el PipedReader es, por ejemplo, 'OutputReader.waitForOutput()'. El escritor es 'ReaderToWriterCopier'. El programa principal es 'SbtRunner', y las fuentes de prueba tienen' SbtRunnerTester' que lo usa. SBT significa http://code.google.com/p/simple-build-tool/ –