Bisakah Anda menjelaskan konsep stream?

186

Saya mengerti bahwa aliran adalah representasi dari urutan byte. Setiap aliran menyediakan sarana untuk membaca dan menulis byte ke backing store yang diberikannya. Tapi apa gunanya arus? Mengapa backing store itu sendiri tidak berinteraksi dengan kita?

Untuk alasan apa pun konsep ini tidak mengklik untuk saya. Saya sudah membaca banyak artikel, tetapi saya pikir saya perlu analogi atau sesuatu.

Rob Sobers
sumber

Jawaban:

234

Kata "aliran" telah dipilih karena mewakili (dalam kehidupan nyata) makna yang sangat mirip dengan apa yang ingin kita sampaikan ketika kita menggunakannya.

Mari kita lupakan toko dukungan sebentar, dan mulai berpikir tentang analogi dengan aliran air. Anda menerima aliran data yang berkelanjutan, seperti air yang terus mengalir di sungai. Anda tidak perlu tahu dari mana data berasal, dan paling sering Anda tidak perlu; baik itu dari file, soket, atau sumber lain, itu tidak masalah. Ini sangat mirip dengan menerima aliran air, di mana Anda tidak perlu tahu dari mana asalnya; baik itu dari danau, air mancur, atau sumber lain, itu tidak masalah.

Yang mengatakan, begitu Anda mulai berpikir bahwa Anda hanya peduli untuk mendapatkan data yang Anda butuhkan, terlepas dari mana asalnya, abstraksi yang dibicarakan orang lain menjadi lebih jelas. Anda mulai berpikir bahwa Anda dapat membungkus stream, dan metode Anda akan tetap bekerja dengan sempurna. Misalnya, Anda bisa melakukan ini:

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);

Seperti yang Anda lihat, menjadi sangat mudah untuk mengubah sumber input Anda tanpa mengubah logika pemrosesan Anda. Misalnya, untuk membaca data Anda dari soket jaringan alih-alih file:

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

Semudah mungkin. Dan keindahan berlanjut, karena Anda dapat menggunakan sumber input apa pun, asalkan Anda dapat membangun aliran "pembungkus" untuk itu. Anda bahkan dapat melakukan ini:

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());

Lihat? Selama metode Anda tidak peduli apa sumber inputnya, Anda dapat menyesuaikan sumber Anda dengan berbagai cara. Abstraksi memungkinkan Anda memisahkan input dari pemrosesan logika dengan cara yang sangat elegan.

Perhatikan bahwa aliran yang kami buat sendiri tidak memiliki backing store, tetapi tetap melayani tujuan kami dengan sempurna.

Jadi, untuk meringkas, aliran hanyalah sumber input, bersembunyi (abstrak) sumber lain. Selama Anda tidak melanggar abstraksi, kode Anda akan sangat fleksibel.

Hosam Aly
sumber
6
Berpikir abstrak (dan menjelaskan) tampaknya ada dalam darah Anda;) Analogi Anda dengan air (dan dengan demikian referensi metaforis) mengingatkan saya pada Omar Khayyam.
java.is.for.desktop
@ HusamAly Penjelasan Anda sangat jelas tetapi ada sesuatu yang membingungkan saya sedikit dalam kode sampel. Konversi eksplisit dari string ke int dilakukan secara otomatis dengan melakukan ReadInt? saya percaya saya bisa melakukan ReadString juga?
Rushino
1
@Rushino Tidak ada konversi dalam kode di atas. Metode ReadIntini didefinisikan di bagian paling atas menggunakan int.Parse, yang menerima string yang dikembalikan dari reader.ReadLine()dan mem-parsingnya. Tentu saja Anda bisa membuat ReadStringmetode serupa . Apakah ini cukup jelas?
Hosam Aly
Baik. Streaming bagi saya adalah abstraksi generik yang paling sederhana dan kuat dalam keseluruhan pemrograman. Memiliki .net basic Stream.Copymembuat hidup jadi lebih mudah di banyak aplikasi.
Felype
38

Intinya adalah Anda tidak perlu tahu apa itu backing store - ini abstraksi. Memang, mungkin bahkan tidak ada toko dukungan - Anda bisa membaca dari jaringan, dan data tidak pernah "disimpan" sama sekali.

Jika Anda dapat menulis kode yang berfungsi baik saat Anda sedang berbicara dengan sistem file, memori, jaringan atau apa pun yang mendukung gagasan aliran, kode Anda jauh lebih fleksibel.

Selain itu, aliran sering dirantai bersama - Anda dapat memiliki aliran yang memampatkan apa pun yang dimasukkan ke dalamnya, menulis formulir terkompresi ke aliran lain, atau yang mengenkripsi data, dll. Di sisi lain akan ada kebalikannya rantai, dekripsi, dekompresi atau apa pun.

Jon Skeet
sumber
Tidakkah berbagai jenis pembaca aliran yang digunakan dalam contoh @HosamAly di atas menyiratkan bahwa Anda tahu apa itu backing store? Saya mengambilnya FileStream, NetworkStream dll ... sedang membaca dari jenis-jenis sumber. Selain itu, apakah ada kasus di mana Anda tidak tahu apa mungkin toko dukungan dan yang akan dipilih secara dinamis saat program berjalan? Saya hanya belum menemukan ini secara pribadi dan ingin tahu lebih banyak.
user137717
Juga, dapat mengalirkan data pipa melalui beberapa proses saat data dihasilkan atau apakah saya memerlukan akses ke dataset lengkap yang ingin saya operasikan ketika saya memulai proses?
user137717
@ user137717: Tidak, jika Anda hanya mengambil StreamReader- atau lebih baik, TextReadermaka kode Anda tidak tahu jenis aliran apa yang mendasari aliran data. Atau lebih tepatnya, ia bisa menggunakan BaseStreamproperti untuk mengetahui tipe - tetapi ini mungkin tipe yang belum pernah dilihat oleh kode Anda. Intinya adalah bahwa Anda seharusnya tidak peduli. Dan ya, Anda benar - benar bisa berakhir menulis kode yang kadang-kadang akan digunakan untuk aliran jaringan dan kadang-kadang digunakan untuk aliran file. Adapun stream data pipa melalui proses - baik yang tidak akan dilakukan di dalam proses ... itu akan menjadi penyedia aliran.
Jon Skeet
30

Tujuan dari aliran ini adalah untuk memberikan lapisan abstraksi antara Anda dan toko dukungan. Jadi blok kode tertentu yang menggunakan aliran tidak perlu peduli jika toko dukungan adalah file disk, memori, dll ...

Torlack
sumber
Ya, ini memungkinkan Anda untuk menukar jenis aliran tanpa melanggar kode Anda. Misalnya, Anda dapat membaca dari file pada satu panggilan dan kemudian buffer memori pada panggilan berikutnya.
Craig
Saya akan menambahkan bahwa alasan Anda ingin melakukan ini adalah bahwa sering kali Anda tidak memerlukan kemampuan mencari file saat membaca atau menulis file, dan dengan demikian jika Anda menggunakan aliran, kode yang sama dapat dengan mudah digunakan untuk membaca dari atau menulis ke soket jaringan, misalnya.
alxp
11

Ini bukan tentang sungai - ini tentang berenang. Jika Anda bisa berenang satu Stream, daripada Anda bisa berenang setiap Stream yang Anda temui.

dmajkic
sumber
7

Untuk menambah ruang gema, aliran adalah abstraksi sehingga Anda tidak peduli tentang toko yang mendasarinya. Masuk akal jika Anda mempertimbangkan skenario dengan dan tanpa streaming.

Sebagian besar file tidak menarik karena stream tidak melakukan banyak hal di atas dan melampaui metode non-stream yang saya kenal. Mari kita mulai dengan file internet.

Jika saya ingin mengunduh file dari internet, saya harus membuka soket TCP, membuat koneksi, dan menerima byte hingga tidak ada lagi byte. Saya harus mengelola buffer, mengetahui ukuran file yang diharapkan, dan menulis kode untuk mendeteksi ketika koneksi terputus dan menangani ini dengan tepat.

Katakanlah saya memiliki semacam objek TcpDataStream. Saya membuatnya dengan informasi koneksi yang sesuai, kemudian membaca byte dari stream hingga dikatakan tidak ada lagi byte. Aliran menangani manajemen buffer, kondisi data akhir, dan manajemen koneksi.

Dengan cara ini, stream membuat I / O lebih mudah. Anda tentu bisa menulis kelas TcpFileDownloader yang melakukan apa yang dilakukan stream, tetapi kemudian Anda memiliki kelas yang khusus untuk TCP. Kebanyakan antarmuka streaming menyediakan metode Read () dan Write (), dan konsep yang lebih rumit ditangani oleh implementasi internal. Karena itu, Anda dapat menggunakan kode dasar yang sama untuk membaca atau menulis ke memori, file disk, soket, dan banyak penyimpanan data lainnya.

OwenP
sumber
5

Visualisasi yang saya gunakan adalah ban berjalan, bukan di pabrik sungguhan karena saya tidak tahu apa-apa tentang itu, tetapi di pabrik kartun tempat barang-barang bergerak di sepanjang garis dan dicap dan dikotak serta dihitung dan diperiksa dengan urutan perangkat bodoh.

Anda memiliki komponen sederhana yang melakukan satu hal, misalnya perangkat untuk meletakkan ceri pada kue. Perangkat ini memiliki aliran input kue tanpa ceri, dan aliran output kue dengan ceri. Ada tiga keuntungan yang layak disebutkan dalam menyusun proses Anda dengan cara ini.

Pertama itu menyederhanakan komponen itu sendiri: jika Anda ingin meletakkan icing cokelat pada kue, Anda tidak perlu perangkat rumit yang tahu segalanya tentang kue, Anda dapat membuat perangkat bodoh yang menempelkan icing cokelat ke apa pun yang dimasukkan ke dalamnya (dalam kartun, sejauh ini tidak mengetahui bahwa item berikutnya bukan kue, itu Wile E. Coyote).

Kedua, Anda dapat membuat produk yang berbeda dengan menempatkan perangkat ke dalam urutan yang berbeda: mungkin Anda ingin kue Anda memiliki lapisan gula di atas ceri, bukan ceri di atas lapisan gula, dan Anda dapat melakukannya hanya dengan menukar perangkat di sekitar pada baris .

Ketiga, perangkat tidak perlu mengelola inventaris, tinju, atau unboxing. Cara paling efisien untuk menggabungkan dan mengemas barang-barang bisa diubah: mungkin hari ini Anda memasukkan kue Anda ke dalam kotak berisi 48 dan mengirimkannya ke luar truk, tetapi besok Anda ingin mengirimkan kotak enam untuk menanggapi pesanan khusus. Perubahan semacam ini dapat diakomodir dengan mengganti atau mengkonfigurasi ulang mesin pada awal dan akhir jalur produksi; mesin ceri di tengah baris tidak harus diubah untuk memproses jumlah item yang berbeda pada satu waktu, itu selalu bekerja dengan satu item pada suatu waktu dan tidak harus tahu bagaimana input atau outputnya dikelompokkan.


sumber
Contoh bagus analogi sebagai penjelasan.
Richie Thomas
5

Ketika saya mendengar tentang streaming untuk pertama kalinya, itu dalam konteks streaming langsung dengan webcam. Jadi, satu host menyiarkan konten video, dan host lainnya menerima konten video. Jadi, apakah streaming ini? Yah ... ya ... tapi streaming langsung adalah konsep konkret, dan saya pikir pertanyaannya mengacu pada konsep abstrak Streaming. Lihat https://en.wikipedia.org/wiki/Live_streaming

Jadi mari kita lanjutkan.


Video bukan satu-satunya sumber daya yang dapat dialirkan. Audio juga dapat di-stream. Jadi kita berbicara tentang Streaming media sekarang. Lihat https://en.wikipedia.org/wiki/Streaming_media . Audio dapat dikirim dari sumber ke target dengan berbagai cara. Jadi mari kita bandingkan beberapa metode pengiriman data satu sama lain.

Pengunduhan file klasik Pengunduhan file klasik tidak terjadi dalam waktu nyata. Sebelum mengambil file untuk digunakan, Anda harus menunggu sampai unduhan selesai.

Unduhan progresif Potongan unduhan progresif mengunduh data dari file media yang dialirkan ke buffer sementara. Data dalam buffer itu bisa diterapkan: data audio-video dalam buffer dapat dimainkan. Karena itu pengguna dapat menonton / mendengarkan file media streaming saat mengunduh. Fast-forwarding dan rewinding adalah mungkin, offcourse dengan buffer. Bagaimanapun, pengunduhan progresif bukanlah streaming langsung.

Streaming Terjadi real-time, dan memotong data. Streaming diimplementasikan dalam siaran langsung. Klien yang mendengarkan siaran tidak bisa maju atau mundur cepat. Dalam video stream, data dibuang setelah pemutaran.

Server Streaming menyimpan koneksi 2 arah dengan kliennya, sementara Server Web menutup koneksi setelah respons server.


Audio dan video bukan satu-satunya hal yang dapat dialirkan. Mari kita lihat konsep stream dalam manual PHP.

stream adalah objek sumber daya yang menunjukkan perilaku yang dapat dialirkan. Yaitu, dapat dibaca dari atau ditulis secara linear, dan mungkin dapat fseek () ke lokasi sewenang-wenang dalam aliran. Tautan: https://www.php.net/manual/en/intro.stream.php

Dalam PHP, sumber daya adalah referensi ke sumber eksternal seperti file, koneksi database. Jadi dengan kata lain, stream adalah sumber yang dapat dibaca atau ditulis. Jadi, Jika Anda bekerja dengan fopen(), maka Anda sudah bekerja dengan stream.

Contoh file teks yang mengalami 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

File zip juga dapat di-stream. Selain itu, streaming tidak terbatas pada file. HTTP, FTP, koneksi SSH dan Input / Output dapat di-stream juga.


Apa yang dikatakan wikipedia tentang konsep Streaming?

Dalam ilmu komputer, aliran adalah urutan elemen data yang tersedia sepanjang waktu. Aliran dapat dianggap sebagai item pada sabuk konveyor yang diproses satu per satu daripada dalam jumlah besar.

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

Tautan Wikipedia ke ini: https://srfi.schemers.org/srfi-41/srfi-41.html dan penulisnya mengatakan ini tentang stream:

Streaming, kadang-kadang disebut daftar malas, adalah struktur data berurutan yang mengandung unsur-unsur yang dihitung hanya berdasarkan permintaan. Stream adalah null atau berpasangan dengan stream di cdr-nya. Karena elemen stream dihitung hanya ketika diakses, stream dapat menjadi tak terbatas.

Jadi Stream sebenarnya adalah struktur data.


Kesimpulan saya: stream adalah sumber yang dapat berisi data yang dapat dibaca dari atau ditulis secara berurutan. Aliran tidak membaca semua yang berisi sumber sekaligus, ia membaca / menulis secara berurutan.


Tautan bermanfaat:

  1. http://www.slideshare.net/auroraeosrose/writing-and-using-php-streams-and-sockets-zendcon-2011 Memberikan presentasi yang sangat jelas
  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
Julian
sumber
4

Itu hanya sebuah konsep, tingkat abstraksi lain yang membuat hidup Anda lebih mudah. Dan mereka semua memiliki antarmuka umum yang berarti Anda dapat menggabungkan mereka dalam cara seperti pipa. Sebagai contoh, encode ke base64, lalu zip lalu tulis ini ke disk dan semuanya dalam satu baris!

vava
sumber
Itu berguna, tentu saja, tetapi saya tidak akan mengatakan itu adalah "inti". Bahkan tanpa rantai itu berguna untuk memiliki abstraksi bersama.
Jon Skeet
Ya kamu benar. Saya telah mengubah kata-kata untuk memperjelas ini.
vava
Yup, itu lebih baik. Semoga Anda tidak berpikir saya terlalu pemilih!
Jon Skeet
3

Penjelasan terbaik aliran yang pernah saya lihat adalah bab 3 dari SICP . (Anda mungkin perlu membaca 2 bab pertama agar masuk akal, tetapi Anda harus tetap melakukannya. :-)

Mereka tidak menggunakan sterams untuk byte sama sekali, melainkan bilangan bulat. Poin besar yang saya dapatkan dari itu adalah:

  • Streaming adalah daftar tertunda
  • Overhead komputasi [dari komputasi yang bersemangat segala sesuatu sebelumnya, dalam beberapa kasus] keterlaluan
  • Kita bisa menggunakan stream untuk mewakili urutan yang panjangnya tak terhingga
Ken
sumber
Saya sebenarnya saat ini pada bab 1 dari SICP. Terima kasih!
Rob Sobers
2
seseorang ingin memberi tahu aliran SICP dari yang lain. fitur penting dari aliran SICP adalah kemalasan , sementara konsep aliran generik menekankan abstraksi pada urutan data .
象 嘉 道
2

Poin lain (Untuk membaca situasi file):

  1. streamdapat memungkinkan Anda untuk melakukan sesuatu yang lain sebelumnya finished reading all content of the file.
  2. Anda dapat menghemat memori, karena tidak perlu memuat semua konten file sekaligus.
vikyd
sumber
1

Pikirkan stream sebagai sumber data abstrak (byte, karakter, dll.). Mereka abstrak mekanisme aktual membaca dari dan menulis ke sumber data konkret, baik itu soket jaringan, file pada disk atau tanggapan dari server web.

Anton Gogolev
sumber
1

Saya pikir Anda perlu mempertimbangkan bahwa backing store itu sendiri seringkali hanyalah abstraksi lain. Aliran memori cukup mudah dimengerti, tetapi file berbeda secara radikal tergantung pada sistem file yang Anda gunakan, apa pun hard drive yang Anda gunakan. Tidak semua stream benar-benar duduk di atas sebuah backing store: aliran jaringan cukup banyak adalah stream.

Inti dari aliran adalah bahwa kita membatasi perhatian kita pada apa yang penting. Dengan memiliki abstraksi standar, kita dapat melakukan operasi umum. Bahkan jika Anda tidak ingin, misalnya, mencari file atau respons HTTP untuk URL hari ini, tidak berarti Anda tidak ingin melakukannya besok.

Aliran awalnya dikandung ketika memori kecil dibandingkan dengan penyimpanan. Hanya membaca file C bisa menjadi beban yang signifikan. Meminimalkan jejak memori sangat penting. Karenanya, sebuah abstraksi di mana sangat sedikit yang perlu dimuat sangat berguna. Saat ini, sama-sama berguna ketika melakukan komunikasi jaringan dan, ternyata, jarang membatasi ketika kita berurusan dengan file. Kemampuan untuk menambahkan hal-hal seperti buffering secara transparan membuatnya lebih berguna.

Julian Birch
sumber
0

Aliran adalah abstrak dari urutan byte. Idenya adalah bahwa Anda tidak perlu tahu dari mana byte berasal, hanya saja Anda dapat membacanya secara standar.

Misalnya, jika Anda memproses data melalui aliran maka tidak masalah dengan kode Anda jika data berasal dari file, koneksi jaringan, string, gumpalan di database dll. Dll.

Tidak ada yang salah dengan berinteraksi dengan backing store itu sendiri kecuali kenyataan bahwa itu mengikat Anda dengan implementasi backing store.

Sean
sumber
0

Aliran adalah abstraksi yang menyediakan sekumpulan metode dan properti standar untuk berinteraksi dengan data. Dengan mengabstraksi dari media penyimpanan yang sebenarnya, kode Anda dapat ditulis tanpa bergantung sepenuhnya pada apa media itu atau bahkan implementasi media itu.

Analogi yang baik mungkin untuk mempertimbangkan tas. Anda tidak peduli terbuat dari apa tas atau apa fungsinya ketika Anda meletakkan barang-barang Anda di dalamnya, selama tas melakukan pekerjaan menjadi tas dan Anda bisa mendapatkan barang-barang Anda kembali. Sebuah aliran mendefinisikan untuk media penyimpanan apa konsep tas mendefinisikan untuk berbagai contoh tas (seperti tas sampah, tas tangan, ransel, dll.) - aturan interaksi.

Jeff Yates
sumber
0

Saya akan singkat, saya hanya kehilangan kata di sini:

Streaming adalah antrian yang biasanya disimpan dalam buffer yang berisi segala jenis data.

(Sekarang, karena kita semua tahu apa itu antrian, tidak perlu menjelaskan ini lebih jauh.)

Marcus
sumber