2011-09-26 12 views
10

Acabo de descubrir que solo tiene una instalación NIO, Java NIO Pipe diseñada para pasar datos entre hilos. ¿Hay alguna ventaja de utilizar este mecanismo sobre el mensaje más convencional que pasa por una cola, como un ArrayBlockingQueue?Java NIO Pipe vs BlockingQueue

+0

Las tuberías pasan por el kernel, raramente son útiles ya que el Selector tiene despertador ... que se implementa a través de pipe en Linux ... – bestsss

+0

¿A qué se debe preocupar? puede registrar tuberías con selectores para recibir notificaciones, ¿cuál es el problema? – raffian

+0

@raffian, para decirlo simplemente, no se puede usar Pipes para IPC y dentro del proceso hay una forma mucho más eficiente de pasar información. – bestsss

Respuesta

6

Por lo general, la forma más sencilla de pasar datos para que otro subproceso sea procesado es utilizar un ExecutorService. Esto completa una cola y un grupo de subprocesos (puede tener un subproceso)

Puede utilizar un conducto cuando tiene una biblioteca que admite canales NIO. También es útil si desea pasar ByteBuffers de datos entre hilos.

De lo contrario, es generalmente simple/más rápido de usar un ArrayBlockingQueue.

Si desea una forma más rápida de intercambiar datos entre hilos, le sugiero que consulte el Exchanger, pero no es tan general como un ArrayBlockingQueue.

The Exchanger and GC-less Java

+0

Gracias, nunca consideré el hecho de que usar el Exchanger minimiza la sobrecarga del GC. Sin embargo, la desventaja del intercambiador es que es sincrónico. Por lo general, solo desea bombear datos a otro subproceso sin tener que esperar a que se recoja. – Maxaon3000

+0

Una tubería tiene un tamaño fijo. El problema es el mismo si el productor está produciendo para que se detenga rápidamente. Si el productor nunca llena el búfer antes de que el consumidor finalice, no tiene que detenerse (en cualquier caso) –

+1

Las tuberías se utilizan para implementar Selector.wakeup, más allá de eso no son muy útiles, ya que las soluciones de memoria son más efectivas y no vayas por el kernel – bestsss

1

supongo que la tubería tendrá una mejor latencia, ya que es muy probable podría ser implementado con corrutinas detrás de las escenas. Por lo tanto, el productor cede inmediatamente al consumidor cuando los datos están disponibles, no cuando el planificador de hilos decide.

Las tuberías en general representan un problema del productor consumidor y es muy probable que se implementen de esta forma para que ambos hilos cooperen y no se tomen en cuenta externamente.

2

Creo que una Tubería NIO fue diseñada para que pueda enviar datos a un canal dentro del bucle selector de una manera segura, es decir, cualquier hilo puede escribir en la tubería y los datos se manejarán en la otra extremo de la tubería, dentro del bucle selector. Cuando escribe en una tubería, hace que el canal en el otro lado sea legible.

+0

Me pregunto acerca de las características de rendimiento de pasar datos entre subprocesos usando un bucle selector sobre una encuesta de cola simple. Además, pasar datos a través de un conducto parece tener el inconveniente de tener que pasar bytes en lugar de objetos a los otros hilos. En otras palabras, te obliga a desarrollar un protocolo de conexión para el intercambio de datos entre hilos. – Maxaon3000

+0

¿Te refieres a un ConcurrentLinkedQueue, correcto? Esa es una gran pregunta. Apuesto mis fichas al ConcurrentLinkedQueue. :) Pero una de las ventajas que veo de las tuberías es que envías un mensaje como todos los demás, en otras palabras, lees desde un canal en lugar de buscar un objeto desde la cola. – chrisapotek

3

Así que después de tener muchos problemas con la tubería (check here) decidí favorecer las colas concurrentes sin bloqueo sobre las tuberías NIO. Así que hice algunos puntos de referencia en ConcurrentLinkedQueue de Java. Vea a continuación:

public static void main(String[] args) throws Exception { 

    ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<String>(); 

    // first test nothing: 

    for (int j = 0; j < 20; j++) { 

     Benchmarker bench = new Benchmarker(); 

     String s = "asd"; 

     for (int i = 0; i < 1000000; i++) { 
      bench.mark(); 
      // s = queue.poll(); 
      bench.measure(); 
     } 

     System.out.println(bench.results()); 

     Thread.sleep(100); 
    } 

    System.out.println(); 

    // first test empty queue: 

    for (int j = 0; j < 20; j++) { 

     Benchmarker bench = new Benchmarker(); 

     String s = "asd"; 

     for (int i = 0; i < 1000000; i++) { 
      bench.mark(); 
      s = queue.poll(); 
      bench.measure(); 
     } 

     System.out.println(bench.results()); 

     Thread.sleep(100); 
    } 

    System.out.println(); 

    // now test polling one element on a queue with size one 

    for (int j = 0; j < 20; j++) { 

     Benchmarker bench = new Benchmarker(); 

     String s = "asd"; 
     String x = "pela"; 

     for (int i = 0; i < 1000000; i++) { 
      queue.offer(x); 
      bench.mark(); 
      s = queue.poll(); 
      bench.measure(); 
      if (s != x) throw new Exception("bad!"); 
     } 

     System.out.println(bench.results()); 

     Thread.sleep(100); 
    } 

    System.out.println(); 

    // now test polling one element on a queue with size two 

    for (int j = 0; j < 20; j++) { 

     Benchmarker bench = new Benchmarker(); 

     String s = "asd"; 
     String x = "pela"; 

     for (int i = 0; i < 1000000; i++) { 
      queue.offer(x); 
      queue.offer(x); 
      bench.mark(); 
      s = queue.poll(); 
      bench.measure(); 
      if (s != x) throw new Exception("bad!"); 
      queue.poll(); 
     } 

     System.out.println(bench.results()); 

     Thread.sleep(100); 
    } 
} 

Los resultados:

totalLogs=1000000, minTime=0, maxTime=85000, avgTime=58.61 (times in nanos) 
totalLogs=1000000, minTime=0, maxTime=5281000, avgTime=63.35 (times in nanos) 
totalLogs=1000000, minTime=0, maxTime=725000, avgTime=59.71 (times in nanos) 
totalLogs=1000000, minTime=0, maxTime=25000, avgTime=58.13 (times in nanos) 
totalLogs=1000000, minTime=0, maxTime=378000, avgTime=58.45 (times in nanos) 
totalLogs=1000000, minTime=0, maxTime=15000, avgTime=57.71 (times in nanos) 
totalLogs=1000000, minTime=0, maxTime=170000, avgTime=58.11 (times in nanos) 
totalLogs=1000000, minTime=0, maxTime=1495000, avgTime=59.87 (times in nanos) 
totalLogs=1000000, minTime=0, maxTime=232000, avgTime=63.0 (times in nanos) 
totalLogs=1000000, minTime=0, maxTime=184000, avgTime=57.89 (times in nanos) 

totalLogs=1000000, minTime=0, maxTime=2600000, avgTime=65.22 (times in nanos) 
totalLogs=1000000, minTime=0, maxTime=850000, avgTime=60.5 (times in nanos) 
totalLogs=1000000, minTime=0, maxTime=150000, avgTime=63.83 (times in nanos) 
totalLogs=1000000, minTime=0, maxTime=43000, avgTime=59.75 (times in nanos) 
totalLogs=1000000, minTime=0, maxTime=276000, avgTime=60.02 (times in nanos) 
totalLogs=1000000, minTime=0, maxTime=457000, avgTime=61.69 (times in nanos) 
totalLogs=1000000, minTime=0, maxTime=204000, avgTime=60.44 (times in nanos) 
totalLogs=1000000, minTime=0, maxTime=154000, avgTime=63.67 (times in nanos) 
totalLogs=1000000, minTime=0, maxTime=355000, avgTime=60.75 (times in nanos) 
totalLogs=1000000, minTime=0, maxTime=338000, avgTime=60.44 (times in nanos) 

totalLogs=1000000, minTime=0, maxTime=345000, avgTime=110.93 (times in nanos) 
totalLogs=1000000, minTime=0, maxTime=396000, avgTime=100.32 (times in nanos) 
totalLogs=1000000, minTime=0, maxTime=298000, avgTime=98.93 (times in nanos) 
totalLogs=1000000, minTime=0, maxTime=1891000, avgTime=101.9 (times in nanos) 
totalLogs=1000000, minTime=0, maxTime=254000, avgTime=103.06 (times in nanos) 
totalLogs=1000000, minTime=0, maxTime=1894000, avgTime=100.97 (times in nanos) 
totalLogs=1000000, minTime=0, maxTime=230000, avgTime=99.21 (times in nanos) 
totalLogs=1000000, minTime=0, maxTime=348000, avgTime=99.63 (times in nanos) 
totalLogs=1000000, minTime=0, maxTime=922000, avgTime=99.53 (times in nanos) 
totalLogs=1000000, minTime=0, maxTime=168000, avgTime=99.12 (times in nanos) 

totalLogs=1000000, minTime=0, maxTime=686000, avgTime=107.41 (times in nanos) 
totalLogs=1000000, minTime=0, maxTime=320000, avgTime=95.58 (times in nanos) 
totalLogs=1000000, minTime=0, maxTime=248000, avgTime=94.94 (times in nanos) 
totalLogs=1000000, minTime=0, maxTime=217000, avgTime=95.01 (times in nanos) 
totalLogs=1000000, minTime=0, maxTime=159000, avgTime=93.62 (times in nanos) 
totalLogs=1000000, minTime=0, maxTime=155000, avgTime=95.28 (times in nanos) 
totalLogs=1000000, minTime=0, maxTime=106000, avgTime=98.57 (times in nanos) 
totalLogs=1000000, minTime=0, maxTime=370000, avgTime=95.01 (times in nanos) 
totalLogs=1000000, minTime=0, maxTime=1836000, avgTime=96.21 (times in nanos) 
totalLogs=1000000, minTime=0, maxTime=212000, avgTime=98.62 (times in nanos) 

Conclusión:

El MaxTime puede dar miedo, pero creo que es seguro concluir que estamos en los 50 nanos variar para el sondeo de un concurrente cola.