En informática , una canalización , también conocida como canalización de datos , es un conjunto de elementos de procesamiento de datos conectados en serie, donde la salida de un elemento es la entrada del siguiente. Los elementos de una canalización suelen ejecutarse en paralelo o en intervalos de tiempo. A menudo se inserta cierta cantidad de almacenamiento intermedio entre los elementos.
El concepto de pipeline es muy utilizado en la vida cotidiana. Por ejemplo, en la cadena de montaje de una fábrica de automóviles, cada tarea específica (como la instalación del motor, la instalación del capó y la instalación de las ruedas) suele realizarse en una estación de trabajo independiente. Las estaciones realizan sus tareas en paralelo, cada una en un automóvil diferente. Una vez que se ha realizado una tarea en un automóvil, se pasa a la siguiente estación. Las variaciones en el tiempo necesario para completar las tareas se pueden compensar mediante un "buffering" (manteniendo uno o más automóviles en un espacio entre las estaciones) o mediante un "stopping" (deteniendo temporalmente las estaciones anteriores) hasta que la siguiente estación esté disponible.
Supongamos que ensamblar un automóvil requiere tres tareas que toman 20, 10 y 15 minutos, respectivamente. Entonces, si las tres tareas se realizaran en una sola estación, la fábrica produciría un automóvil cada 45 minutos. Al utilizar un sistema de tres estaciones, la fábrica produciría el primer automóvil en 45 minutos y, luego, uno nuevo cada 20 minutos.
Como muestra este ejemplo, la segmentación no reduce la latencia , es decir, el tiempo total que tarda un elemento en pasar por todo el sistema. Sin embargo, sí aumenta el rendimiento del sistema , es decir, la velocidad a la que se procesan los elementos nuevos después del primero.
En informática , una tubería o canalización de datos [1] es un conjunto de elementos de procesamiento de datos conectados en serie, donde la salida de un elemento es la entrada del siguiente. Los elementos de una tubería se ejecutan a menudo en paralelo o en intervalos de tiempo. A menudo se inserta cierta cantidad de almacenamiento intermedio entre los elementos.
Los procesos relacionados con la informática incluyen:
Como el rendimiento de una tubería no puede ser mejor que el de su elemento más lento, el diseñador debe intentar dividir el trabajo y los recursos entre las etapas de modo que todas tarden lo mismo en completar sus tareas. En el ejemplo de ensamblaje de automóviles anterior, si las tres tareas demoraran 15 minutos cada una, en lugar de 20, 10 y 15 minutos, la latencia seguiría siendo de 45 minutos, pero se terminaría un automóvil nuevo cada 15 minutos, en lugar de 20.
En circunstancias ideales, si todos los elementos de procesamiento están sincronizados y tardan la misma cantidad de tiempo en procesarse, cada elemento puede recibir cada elemento en el mismo momento en que es liberado por el anterior, en un solo ciclo de reloj . De esa manera, los elementos fluirán a través de la tubería a una velocidad constante, como las olas en un canal de agua. En estas "tuberías de ondas", [2] no se necesita sincronización ni almacenamiento intermedio entre las etapas, además del almacenamiento necesario para los elementos de datos.
En términos más generales, el almacenamiento en búfer entre las etapas de la cadena de procesamiento es necesario cuando los tiempos de procesamiento son irregulares o cuando se pueden crear o destruir elementos a lo largo de la cadena de procesamiento. Por ejemplo, en una cadena de procesamiento de gráficos que procesa triángulos que se van a representar en la pantalla, un elemento que verifica la visibilidad de cada triángulo puede descartar el triángulo si es invisible o puede generar dos o más piezas triangulares del elemento si están parcialmente ocultas. El almacenamiento en búfer también es necesario para adaptarse a las irregularidades en las velocidades a las que la aplicación envía elementos a la primera etapa y consume la salida de la última.
El búfer entre dos etapas puede ser simplemente un registro de hardware con una lógica de sincronización y señalización adecuada entre las dos etapas. Cuando una etapa A almacena un elemento de datos en el registro, envía una señal de "datos disponibles" a la siguiente etapa B. Una vez que B ha utilizado esos datos, responde con una señal de "datos recibidos" a A. La etapa A se detiene, esperando esta señal, antes de almacenar el siguiente elemento de datos en el registro. La etapa B se detiene, esperando la señal de "datos disponibles", si está lista para procesar el siguiente elemento pero la etapa A aún no lo ha proporcionado.
Si los tiempos de procesamiento de un elemento son variables, es posible que todo el pipeline deba detenerse a menudo, esperando a que ese elemento y todos los anteriores consuman los elementos en sus buffers de entrada. La frecuencia de tales paradas del pipeline se puede reducir proporcionando espacio para más de un elemento en el buffer de entrada de esa etapa. Este tipo de buffer de múltiples elementos suele implementarse como una cola de primero en entrar, primero en salir . Es posible que la etapa anterior deba detenerse cuando la cola se llena, pero la frecuencia de esos eventos disminuirá a medida que se proporcionen más ranuras de buffer. La teoría de colas puede indicar la cantidad de ranuras de buffer necesarias, dependiendo de la variabilidad de los tiempos de procesamiento y del rendimiento deseado.
Si alguna etapa lleva (o puede llevar) mucho más tiempo que las demás y no se puede acelerar, el diseñador puede proporcionar dos o más elementos de procesamiento para llevar a cabo esa tarea en paralelo, con un único búfer de entrada y un único búfer de salida. A medida que cada elemento termina de procesar su elemento de datos actual, lo entrega al búfer de salida común y toma el siguiente elemento de datos del búfer de entrada común. Este concepto de canalización "no lineal" o "dinámica" se ejemplifica en las tiendas o bancos que tienen dos o más cajeros que atienden a los clientes de una única cola de espera.
En algunas aplicaciones, el procesamiento de un elemento Y por parte de una etapa A puede depender de los resultados o el efecto del procesamiento de un elemento X anterior por parte de una etapa B posterior del proceso. En ese caso, la etapa A no puede procesar correctamente el elemento Y hasta que el elemento X haya pasado por la etapa B.
Esta situación se produce muy a menudo en las secuencias de instrucciones. Por ejemplo, supongamos que Y es una instrucción aritmética que lee el contenido de un registro que se suponía que había sido modificado por una instrucción anterior X. Sea A la etapa que obtiene los operandos de la instrucción y B la etapa que escribe el resultado en el registro especificado. Si la etapa A intenta procesar la instrucción Y antes de que la instrucción X llegue a la etapa B, el registro puede seguir conteniendo el valor anterior y el efecto de Y sería incorrecto.
Para gestionar correctamente estos conflictos, la tubería debe contar con circuitos o lógica adicionales que los detecten y tomen las medidas adecuadas. Las estrategias para hacerlo incluyen:
Para implementarse de manera efectiva, las canalizaciones de datos necesitan una estrategia de programación de CPU para enviar trabajo a los núcleos de CPU disponibles y el uso de estructuras de datos en las que operarán las etapas de la canalización. Por ejemplo, los derivados de UNIX pueden canalizar comandos que conecten la E/S estándar de varios procesos, utilizando las canalizaciones implementadas por el sistema operativo. Algunos sistemas operativos [ ejemplo necesario ] pueden proporcionar una sintaxis similar a UNIX para encadenar varias ejecuciones de programas en una canalización, pero implementar esta última como una ejecución serial simple, en lugar de una canalización verdadera, es decir, esperando a que cada programa termine antes de comenzar el siguiente. [ cita requerida ]
Los enfoques de nivel inferior pueden depender de los subprocesos proporcionados por el sistema operativo para programar el trabajo en las etapas: tanto las implementaciones basadas en grupos de subprocesos como las basadas en un subproceso por etapa son viables y existen. [3]
Existen otras estrategias que se basan en la multitarea cooperativa y que no necesitan múltiples subprocesos de ejecución y, por lo tanto, núcleos de CPU adicionales, como el uso de un programador round-robin con un marco basado en corrutinas. En este contexto, cada etapa puede instanciarse con su propia corrutina, devolviendo el control al programador después de terminar su tarea circular. Este enfoque puede requerir un control cuidadoso sobre las etapas del proceso para evitar que abusen de su franja de tiempo.
Un sistema canalizado generalmente requiere más recursos (elementos de circuito, unidades de procesamiento, memoria de computadora, etc.) que uno que ejecuta un lote a la vez, porque sus etapas no pueden compartir esos recursos y porque puede necesitarse almacenamiento en búfer y lógica de sincronización adicional entre los elementos.
Además, la transferencia de elementos entre elementos de procesamiento separados puede aumentar la latencia, especialmente en procesos largos.
El costo adicional de complejidad del pipeline puede ser considerable si existen dependencias entre el procesamiento de diferentes elementos, especialmente si se utiliza una estrategia de adivinación y retroceso para manejarlas. De hecho, el costo de implementar esa estrategia para conjuntos de instrucciones complejos ha motivado algunas propuestas radicales para simplificar la arquitectura informática , como RISC y VLIW . Los compiladores también se han visto sobrecargados con la tarea de reorganizar las instrucciones de la máquina para mejorar el rendimiento de los pipelines de instrucciones.
Es cierto que en los últimos años las demandas sobre las aplicaciones y su hardware subyacente han sido significativas. Por ejemplo, construir pipelines con aplicaciones de un solo nodo que rastrean los datos fila por fila ya no es factible con el volumen y la variedad de big data . Sin embargo, con la llegada de motores de análisis de datos como Hadoop o, más recientemente, Apache Spark , ha sido posible distribuir grandes conjuntos de datos entre múltiples nodos de procesamiento, lo que permite que las aplicaciones alcancen cotas de eficiencia cientos de veces mayores de lo que se creía posible antes. El efecto de esto hoy es que incluso una PC de nivel medio que use procesamiento distribuido de esta manera puede manejar la construcción y ejecución de pipelines de big data. [4]