¿Puedes explicar el concepto de corrientes?


186

Entiendo que una secuencia es una representación de una secuencia de bytes. Cada flujo proporciona medios para leer y escribir bytes en su almacén de respaldo dado. Pero, ¿cuál es el punto de la corriente? ¿Por qué no es la tienda de respaldo con la que interactuamos?

Por alguna razón, este concepto simplemente no está haciendo clic para mí. He leído un montón de artículos, pero creo que necesito una analogía o algo así.

Respuestas:


234

La palabra "transmisión" ha sido elegida porque representa (en la vida real) un significado muy similar a lo que queremos transmitir cuando la usamos.

Olvidemos un poco la tienda de respaldo y comencemos a pensar en la analogía con una corriente de agua. Recibe un flujo continuo de datos, al igual que el agua fluye continuamente en un río. No necesariamente sabe de dónde provienen los datos, y la mayoría de las veces no es necesario; ya sea desde un archivo, un socket o cualquier otra fuente, realmente no debería (no debería) importar. Esto es muy similar a recibir una corriente de agua, por lo que no necesita saber de dónde viene; ya sea de un lago, una fuente o cualquier otra fuente, realmente no debería importar.

Dicho esto, una vez que empiezas a pensar que solo te importa obtener los datos que necesitas, independientemente de dónde provienen, las abstracciones de las que hablaron otras personas se vuelven más claras. Empiezas a pensar que puedes envolver flujos, y tus métodos seguirán funcionando perfectamente. Por ejemplo, podrías hacer esto:

int ReadInt(StreamReader reader) { return Int32.Parse(reader.ReadLine()); }

// in another method:
Stream fileStream = new FileStream("My Data.dat");
Stream zipStream = new ZipDecompressorStream(fileStream);
Stream decryptedStream = new DecryptionStream(zipStream);
StreamReader reader = new StreamReader(decryptedStream);

int x = ReadInt(reader);

Como puede ver, se vuelve muy fácil cambiar su fuente de entrada sin cambiar su lógica de procesamiento. Por ejemplo, para leer sus datos desde un socket de red en lugar de un archivo:

Stream stream = new NetworkStream(mySocket);
StreamReader reader = new StreamReader(stream);
int x = ReadInt(reader);

Tan fácil como puede ser. Y la belleza continúa, ya que puede usar cualquier tipo de fuente de entrada, siempre y cuando pueda construir un "contenedor" de flujo para ella. Incluso podrías hacer esto:

public class RandomNumbersStreamReader : StreamReader {
    private Random random = new Random();

    public String ReadLine() { return random.Next().ToString(); }
}

// and to call it:
int x = ReadInt(new RandomNumbersStreamReader());

¿Ver? Siempre que a su método no le importe cuál es la fuente de entrada, puede personalizar su fuente de varias maneras. La abstracción le permite desacoplar la entrada de la lógica de procesamiento de una manera muy elegante.

Tenga en cuenta que la transmisión que creamos nosotros mismos no tiene una tienda de respaldo, pero aún cumple nuestros propósitos perfectamente.

Entonces, para resumir, una secuencia es solo una fuente de entrada, ocultando (abstrayendo) otra fuente. Mientras no rompa la abstracción, su código será muy flexible.


66
El pensamiento abstracto (y la explicación) parece estar en tu sangre;) Tu analogía con el agua (y por lo tanto referencias metafóricas) me recordó a Omar Khayyam.
java.is.for.desktop

@HosamAly Su explicación es muy clara, pero algo me confunde un poco en el código de muestra. La conversión explícita de cadena a int se realiza automáticamente haciendo ReadInt? Creo que podría hacer ReadString también?
Rushino

1
@Rushino No hay conversiones en el código anterior. El método ReadIntse define en la parte superior usando int.Parse, que recibe la cadena devuelta reader.ReadLine()y la analiza. Por supuesto, podrías crear un ReadStringmétodo similar . ¿Es esto lo suficientemente claro?
Hosam Aly

Así poner. Las transmisiones para mí son las abstracciones genéricas más simples y poderosas en toda la programación. Tener .net basic Stream.Copyhace la vida mucho más fácil en muchas aplicaciones.
Felype

38

El punto es que no debería tener que saber cuál es la tienda de respaldo: es una abstracción sobre ella. De hecho, es posible que ni siquiera haya una tienda de respaldo: podría estar leyendo desde una red y los datos nunca se "almacenan" en absoluto.

Si puede escribir código que funcione, ya sea que esté hablando con un sistema de archivos, memoria, una red o cualquier otra cosa que respalde la idea de transmisión, su código es mucho más flexible.

Además, las secuencias a menudo se encadenan juntas: puede tener una secuencia que comprima lo que se le pone, escribir el formulario comprimido en otra secuencia, o una que cifre los datos, etc. En el otro extremo habría lo contrario cadena, descifrar, descomprimir o lo que sea.


¿No implican los diferentes tipos de lectores de flujo utilizados en el ejemplo de @HosamAly anterior que usted sabe cuál es la tienda de respaldo? Supongo que FileStream, NetworkStream, etc ... están leyendo ese tipo de fuentes. Además, ¿hay casos en los que no sabe cuál podría ser el almacén de respaldo y que se elegirían dinámicamente mientras se ejecuta el programa? Simplemente no me he encontrado personalmente con esto y me gustaría saber más.
usuario137717

Además, ¿se pueden transmitir datos de canalización a través de algún proceso a medida que se generan datos o necesito acceso al conjunto de datos completo en el que quiero operar cuando empiezo el proceso?
user137717

@ user137717: No, si solo toma un StreamReader- o mejor, TextReaderentonces su código no sabe qué tipo de flujo subyace al flujo de datos. O más bien, puede usar la BaseStreampropiedad para averiguar el tipo, pero puede ser un tipo que su código nunca haya visto antes. El punto es que no debería importarte. Y sí, puede absolutamente terminar la escritura de código que a veces ser utilizado para un flujo de red y, a veces se utiliza para una secuencia de archivo. En cuanto a los flujos que canalizan datos a través de un proceso, bueno, eso no se haría dentro del proceso ... sería el proveedor del flujo.
Jon Skeet

30

El objetivo de la transmisión es proporcionar una capa de abstracción entre usted y la tienda de respaldo. Por lo tanto, un bloque de código dado que usa una secuencia no necesita preocuparse si el almacén de respaldo es un archivo de disco, memoria, etc.


Sí, te permite intercambiar el tipo de transmisión sin romper tu código. Por ejemplo, puede leer desde un archivo en una llamada y luego un búfer de memoria en la siguiente.
Craig

Agregaría que la razón por la que desearía hacer esto es que a menudo no necesita la capacidad de búsqueda de archivos al leer o escribir un archivo, y por lo tanto, si usa una secuencia, ese mismo código se puede usar fácilmente para leer o escribir en una toma de red, por ejemplo.
alxp

11

No se trata de arroyos, se trata de nadar. Si puedes nadar una corriente, entonces puedes nadar cualquier corriente que encuentres.


7

Para agregar a la cámara de eco, la secuencia es una abstracción, por lo que no le importa la tienda subyacente. Tiene más sentido cuando considera escenarios con y sin secuencias.

Los archivos no son interesantes en su mayor parte porque las transmisiones no hacen mucho más allá de lo que hacen los métodos no basados ​​en transmisiones con los que estoy familiarizado. Comencemos con los archivos de internet.

Si deseo descargar un archivo de Internet, tengo que abrir un socket TCP, establecer una conexión y recibir bytes hasta que no haya más bytes. Tengo que administrar un búfer, conocer el tamaño del archivo esperado y escribir código para detectar cuándo se cae la conexión y manejar esto de manera adecuada.

Digamos que tengo algún tipo de objeto TcpDataStream. Lo creo con la información de conexión adecuada, luego leo los bytes de la transmisión hasta que dice que no hay más bytes. La secuencia maneja la gestión del búfer, las condiciones de fin de datos y la gestión de la conexión.

De esta manera, las transmisiones facilitan la E / S. Ciertamente, podría escribir una clase TcpFileDownloader que haga lo que hace la secuencia, pero luego tiene una clase que es específica de TCP. La mayoría de las interfaces de flujo simplemente proporcionan un método Read () y Write (), y la implementación interna maneja los conceptos más complicados. Debido a esto, puede usar el mismo código básico para leer o escribir en la memoria, archivos de disco, sockets y muchos otros almacenes de datos.


5

La visualización que utilizo son cintas transportadoras, no en fábricas reales porque no sé nada de eso, sino en fábricas de dibujos animados donde los artículos se mueven a lo largo de las líneas y se estampan y encajonan y cuentan y verifican mediante una secuencia de dispositivos tontos.

Tiene componentes simples que hacen una cosa, por ejemplo, un dispositivo para poner una cereza en un pastel. Este dispositivo tiene un flujo de entrada de pasteles sin cereza y un flujo de salida de pasteles con cerezas. Hay tres ventajas que vale la pena mencionar para estructurar su procesamiento de esta manera.

En primer lugar, simplifica los componentes en sí mismos: si desea poner glaseado de chocolate en un pastel, no necesita un dispositivo complicado que sepa todo sobre los pasteles, puede crear un dispositivo tonto que adhiera el glaseado de chocolate a lo que sea que se alimente ( las caricaturas, esto va tan lejos como no saber que el siguiente elemento no es un pastel, es Wile E. Coyote).

En segundo lugar, puede crear diferentes productos colocando los dispositivos en diferentes secuencias: tal vez desee que sus pasteles tengan glaseado encima de la cereza en lugar de cereza encima de la guinda, y puede hacerlo simplemente intercambiando los dispositivos en la línea .

En tercer lugar, los dispositivos no necesitan administrar inventario, boxeo o unboxing. La forma más eficiente de agregar y empaquetar cosas es cambiante: tal vez hoy esté colocando sus pasteles en cajas de 48 y enviándolos por camión, pero mañana desea enviar cajas de seis en respuesta a pedidos personalizados. Este tipo de cambio puede adaptarse reemplazando o reconfigurando las máquinas al comienzo y al final de la línea de producción; la máquina de cerezas en el medio de la línea no tiene que cambiarse para procesar un número diferente de elementos a la vez, siempre funciona con un elemento a la vez y no tiene que saber cómo es su entrada o salida siendo agrupado


Gran ejemplo de analogía como explicación.
Richie Thomas

5

Cuando escuché sobre la transmisión por primera vez, fue en el contexto de la transmisión en vivo con una cámara web. Entonces, un host está transmitiendo contenido de video y el otro está recibiendo el contenido de video. Entonces, ¿esto es transmisión? Bueno ... sí ... pero una transmisión en vivo es un concepto concreto, y creo que la pregunta se refiere al concepto abstracto de Streaming. Ver https://en.wikipedia.org/wiki/Live_streaming

Así que sigamos adelante.


El video no es el único recurso que se puede transmitir. El audio también se puede transmitir. Estamos hablando de Streaming de medios ahora. Ver https://en.wikipedia.org/wiki/Streaming_media . El audio se puede entregar desde el origen al destino de varias maneras. Así que comparemos algunos métodos de entrega de datos entre sí.

Descarga de archivos clásicos La descarga de archivos clásicos no se realiza en tiempo real. Antes de utilizar el archivo, deberá esperar hasta que se complete la descarga.

Descarga progresiva Los fragmentos de descarga progresiva descargan datos del archivo multimedia transmitido a un búfer temporal. Los datos en ese búfer son viables: los datos de audio y video en el búfer se pueden reproducir. Debido a eso, los usuarios pueden ver / escuchar el archivo multimedia transmitido durante la descarga. Es posible el avance rápido y el rebobinado, fuera de curso dentro del búfer. De todos modos, la descarga progresiva no es transmisión en vivo.

La transmisión ocurre en tiempo real y fragmenta los datos. La transmisión se implementa en transmisiones en vivo. Los clientes que escuchan la transmisión no pueden avanzar o retroceder rápidamente. En las transmisiones de video, los datos se descartan después de la reproducción.

Un servidor de transmisión mantiene una conexión bidireccional con su cliente, mientras que un servidor web cierra la conexión después de una respuesta del servidor.


El audio y el video no son lo único que se puede transmitir. Echemos un vistazo al concepto de flujos en el manual de PHP.

una secuencia es un objeto de recurso que exhibe un comportamiento de transmisión. Es decir, puede leerse o escribirse de forma lineal, y puede ser capaz de buscar fseek () en una ubicación arbitraria dentro de la secuencia. Enlace: https://www.php.net/manual/en/intro.stream.php

En PHP, un recurso es una referencia a una fuente externa como un archivo, conexión de base de datos. En otras palabras, una secuencia es una fuente que se puede leer o escribir. Entonces, si trabajó con fopen(), ya trabajó con transmisiones.

Un ejemplo de un archivo de texto que está sujeto a Streaming:

// Let's say that cheese.txt is a file that contains this content: 
// I like cheese, a lot! My favorite cheese brand is Leerdammer.
$fp = fopen('cheese.txt', 'r');

$str8 = fread($fp, 8); // read first 8 characters from stream. 

fseek($fp, 21); // set position indicator from stream at the 21th position (0 = first position)
$str30 = fread($fp, 30); // read 30 characters from stream

echo $str8; // Output: I like c 
echo $str30; // Output: My favorite cheese brand is L

Los archivos zip también se pueden transmitir. Además de eso, la transmisión no se limita a los archivos. Las conexiones HTTP, FTP, SSH y Entrada / Salida también se pueden transmitir.


¿Qué dice wikipedia sobre el concepto de Streaming?

En informática, una secuencia es una secuencia de elementos de datos disponibles a lo largo del tiempo. Una corriente puede considerarse como elementos en una cinta transportadora que se procesan uno a la vez en lugar de en grandes lotes.

Ver: https://en.wikipedia.org/wiki/Stream_%28computing%29 .

Wikipedia enlaza con esto: https://srfi.schemers.org/srfi-41/srfi-41.html y los escritores tienen esto que decir sobre las transmisiones:

Las secuencias, a veces llamadas listas diferidas, son una estructura de datos secuenciales que contiene elementos calculados solo a pedido. Una secuencia es nula o es un par con una secuencia en su cdr. Dado que los elementos de una secuencia se calculan solo cuando se accede a ellos, las secuencias pueden ser infinitas.

Entonces, un Stream es en realidad una estructura de datos.


Mi conclusión: una secuencia es una fuente que puede contener datos que se pueden leer o escribir de forma secuencial. Una secuencia no lee todo lo que contiene la fuente a la vez, sino que lee / escribe secuencialmente.


Enlaces útiles:

  1. http://www.slideshare.net/auroraeosrose/writing-and-using-php-streams-and-sockets-zendcon-2011 Proporciona una presentación muy clara
  2. https://www.sk89q.com/2010/04/introduction-to-php-streams/
  3. http://www.netlingo.com/word/stream-or-streaming.php
  4. http://www.brainbell.com/tutorials/php/Using_PHP_Streams.htm
  5. http://www.sitepoint.com/php-streaming-output-buffering-explained/
  6. http://php.net/manual/en/wrappers.php
  7. http://www.digidata-lb.com/streaming/Streaming_Proposal.pdf
  8. http://www.webopedia.com/TERM/S/streaming.html
  9. https://en.wikipedia.org/wiki/Stream_%28computing%29
  10. https://srfi.schemers.org/srfi-41/srfi-41.html

4

Es solo un concepto, otro nivel de abstracción que te hace la vida más fácil. Y todos tienen una interfaz común, lo que significa que puede combinarlos de forma similar a una tubería. Por ejemplo, codifique en base64, luego comprima y luego escriba esto en el disco y todo en una línea.


Eso es útil, ciertamente, pero no diría que es el "punto central". Incluso sin encadenar es útil tener una abstracción común.
Jon Skeet

Si, tienes razón. He cambiado las palabras para aclarar esto.
vava

Sí, eso está mejor. ¡Espero que no hayas pensado que estaba siendo demasiado exigente!
Jon Skeet

3

La mejor explicación de las transmisiones que he visto es el capítulo 3 de SICP . (Es posible que deba leer los primeros 2 capítulos para que tenga sentido, pero de todos modos debería hacerlo. :-)

No usan sterams para bytes en absoluto, sino enteros. Los grandes puntos que obtuve fueron:

  • Las transmisiones son listas retrasadas
  • La sobrecarga computacional [de calcular ansiosamente todo antes de tiempo, en algunos casos] es indignante
  • Podemos usar flujos para representar secuencias que son infinitamente largas

Actualmente estoy actualmente en el capítulo 1 de SICP. ¡Gracias!
Rob Sobers

2
a uno le gustaría distinguir la transmisión SICP de los demás. Una característica importante del flujo de SICP es la pereza , mientras que el concepto de flujo genérico enfatiza la abstracción en las secuencias de datos .
象 嘉 道

2

Otro punto (para leer la situación del archivo):

  1. stream puede permitirte hacer algo más antes finished reading all content of the file .
  2. puede ahorrar memoria porque no necesita cargar todo el contenido del archivo a la vez.

1

Piense en los flujos como una fuente abstracta de datos (bytes, caracteres, etc.). Resumen la mecánica real de leer y escribir en la fuente de datos concreta, ya sea un socket de red, un archivo en un disco o una respuesta del servidor web.


1

Creo que debe tener en cuenta que la tienda de respaldo en sí misma es a menudo solo otra abstracción. Un flujo de memoria es bastante fácil de entender, pero un archivo es radicalmente diferente dependiendo del sistema de archivos que esté utilizando, no importa qué disco duro esté utilizando. De hecho, no todas las transmisiones se ubican en la parte superior de una tienda de respaldo: las transmisiones de red son simplemente transmisiones.

El punto de una transmisión es que restringimos nuestra atención a lo que es importante. Al tener una abstracción estándar, podemos realizar operaciones comunes. Incluso si no desea, por ejemplo, buscar un archivo o una respuesta HTTP para URL hoy, no significa que no desee hacerlo mañana.

Las secuencias se concibieron originalmente cuando la memoria era pequeña en comparación con el almacenamiento. Solo leer un archivo C podría ser una carga significativa. Minimizar la huella de memoria fue extremadamente importante. Por lo tanto, una abstracción en la que se necesitaba cargar muy poco era muy útil. Hoy en día, es igualmente útil cuando se realiza una comunicación de red y resulta que rara vez es tan restrictivo cuando tratamos con archivos. La capacidad de agregar de forma transparente cosas como el almacenamiento en búfer de manera general lo hace aún más útil.


0

Una secuencia es un resumen de una secuencia de bytes. La idea es que no necesita saber de dónde provienen los bytes, solo que puede leerlos de manera estandarizada.

Por ejemplo, si procesa datos a través de una secuencia, no importa a su código si los datos provienen de un archivo, una conexión de red, una cadena, un blob en una base de datos, etc., etc.

No hay nada de malo en interactuar con la tienda de respaldo en sí, excepto por el hecho de que lo vincula con la implementación de la tienda de respaldo.


0

Una secuencia es una abstracción que proporciona un conjunto estándar de métodos y propiedades para interactuar con los datos. Al abstraerse del medio de almacenamiento real, su código se puede escribir sin depender totalmente de lo que ese medio es o incluso la implementación de ese medio.

Una buena analogía podría ser considerar una bolsa. No le importa de qué está hecha una bolsa o qué hace cuando coloca sus cosas en ella, siempre que la bolsa realice el trabajo de ser una bolsa y pueda recuperar sus cosas. Un flujo define para los medios de almacenamiento lo que el concepto de bolsa define para diferentes instancias de una bolsa (como bolsa de basura, bolso, mochila, etc.): las reglas de interacción.


0

Lo mantendré breve, solo me faltaba la palabra aquí:

Las secuencias son colas generalmente almacenadas en un búfer que contiene cualquier tipo de datos.

(Ahora, como todos sabemos qué son las colas, no hay necesidad de explicar esto más adelante).

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.