Node.js - Stream Nedir? Nasıl Oluşturulur? - Yazılım Mimarileri ve Tasarım Desenleri Üzerine

Node.js – Stream Nedir? Nasıl Oluşturulur?

Merhaba,

Bu içeriğimizde, verilerin bütün olarak değil parça parça transfer edilmesini sağlayan Stream yapıları üzerine konuşuyor olacağız.

Stream Nedir?

Stream, yukarıda da değinildiği gibi büyük boyutlu bir veriyi bir yerden başka bir yere transfer ederken bütün olarak değil de parça parça transfer edilmesini sağlayan yayın ya da akış şeklinde tarif edilebilen bir kavramdır. Bu yapının işlevine en güzel örneği youtube olarak verebiliriz. İlgili platformda izlenen herhangi bir videonun tam olarak yüklenmesine gerek duyulmaksızın parça parça transfer sağlanmakta ve onlarca boyuttaki video bu şekilde bekleme olmaksızın rahatça izlenmektedir. Bizler izledikçe videonun akışı devam etmekte ve geri kalan verileride zamanla bilgisayarımıza indirilmektedir.

Streamleri yapısal olarak bu şekilde tarif edebiliriz lakin Node.js’e özel bazı faktörleride yapılarında barındırmaktadırlar. Node.js’de Streamlar, aslen birer event emitter‘dır. Dolayısıyla, akış anında her bir parça sunulduğu anda bundan bizim haberimiz olmaktadır.

Teknik olarak akıştaki her bir parça bir Buffer nesnesidir ve “Chunk” sıfatıyla temsil edilmektedir. Her chunk akışı sağlandığında “data” isimli event tetiklenmektedir. Tüm veri transferi sağlandığında ise “end” eventı tetiklenecektir.

Bu tanımlamalardan sonra sıra Streamlerin nasıl oluşturulduğunu incelemeye geldi.

Streamlar yönleri bakımından “Readable(Okunabilir)”, “Writeable(Yazılabilir)” ve “Readable/Writeable(Hem Okunabilir, Hem Yazılabilir) olmak üzere üç farklı kategoride değerlendirilmektedir.

Okunabilir Stream Oluşturmak

“Readable(Okunabilir)” stream yapısı bir veriyi parça parça okumada kullandığımız bir yaklaşımdır.
Örnek olarak aşağıdaki kod bloğunu inceleyebilirsiniz.

//Dosyaya ulaşmak için fs kütüphanesini getiriyoruz.
const fs = require("fs");
//Geriye EventEmitter döndürecek createReadStream fonksiyonu ile dosyayı
//Stream olarak okuyoruz.
const readStream = fs.createReadStream("video.avi");

//Şimdi her data geldiğinde data gelip gelmediğini bilmemiz gerekiyor.
//Data geliyorsa eğer EventEmitter "data" isimli olayı tetikleyecektir.
//Dolayısıyla ilgili fonksiyonu oluşturuyorum.
readStream.on("data", (chunk) => {
    console.log(`${chunk.length} : Veri geldi.`);
});

//Eğer akış sona erdiyse EventEmitter nesnemiz "end" isimli olayı tetikleyecektir.
//Yine fonksiyonumu tanımlıyorum.
readStream.on("end", () => {
    console.log("Veri akışı son buldu.");
});

Görüldüğü üzere örneğimizde kodlar arasında gerekli açıklamaları yaptığım için ek bir açıklamada bulunmayacağım lakin veriyi stream ile nasıl okunduğunu incelemiş bulunmaktayız. Bu çalışma neticesinde aşağıdaki sonucu almaktayız;
Node.js - Stream Nedir? Nasıl Oluşturulur?

Okunabilir streamlerde okunan verinin yüzdelik durumunu görebilmek için aşağıdaki gibi bir çalışma yapabiliriz. Tabi burada yukarıdaki örnekten farklı bir çalışma ve dosya üzerinden örneklendirme yapıyorum.

const file = require("fs");

const stream = file.createReadStream("dosya.rar");
file.stat("dosya.rar", (error, data) => {
    if (error)
        throw error;

    const fileSize = data.size;
    let chunkSize = 0, oldSize = 0, lastSize = 0;
    stream.on("data", chunk => {
        chunkSize += chunk.length;
        lastSize = Math.round(chunkSize * 100 / fileSize);
        if (oldSize != lastSize)
            console.log(`${lastSize}%`);
        oldSize = lastSize;
    });
});

Node.js – Stream Nedir? Nasıl Oluşturulur?

Yazılabilir Stream Oluşturmak

Yazılabilir streamlerede örnek olarak; okunabilir stremden elde ettiğimiz verileri alıp yazılabilir stream aracılığıyla başka bir noktaya transfer etmek için kullanacağım.

const fs = require("fs");
const readStream = fs.createReadStream("video.avi");
const writeStream = fs.createWriteStream("video2.avi");
readStream.on("data", (chunk) => {
    console.log(`${chunk.length} : Veri geldi.`);
});
//readStream'a writeStream'ı pipe olarak vermekteyim.
readStream.pipe(writeStream);
//Yazım işlemi bittiği vakit "finish" olayı tetiklenecektir.
writeStream.on("finish", () => {
    console.log("Yazım işlemi son buldu.");
})
readStream.on("end", () => {
    console.log("Veri akışı son buldu.");
});

Yukarıdaki kod bloğunu incelerseniz eğer okunabilir stream’dan(readStream) gelen verileri “pipe” fonksiyonu aracılığıyla yazılabilir stream’e(writeStream) atamış bulunmaktayım. Veri her okunduğunda ilgili pipe tetiklenecek ve yazılabilir stream aracılığıyla belirtilen dosyaya transfer edilecektir. Ayrıca yazılabilir stream’ler de komple işlemin bittiğini “finish” eventı ile öğrenebilmekteyiz.

Node.js - Stream Nedir? Nasıl Oluşturulur?

İçeriğimizi zenginleştirmek adına yazılabilir streamlerde de yüzdelik durumu gösterecek algoritmayı oluşturmak istersek eğer;

const file = require("fs");

const stream = file.createReadStream("dosya.rar");
const writeStream = file.createWriteStream("dosya2.rar");
file.stat("dosya.rar", (error, data) => {
    if (error)
        throw error;

    const fileSize = data.size;
    let chunkSize = 0, oldSize = 0, lastSize = 0;
    stream.on("data", chunk => {
        chunkSize += chunk.length;
        lastSize = Math.round(chunkSize * 100 / fileSize);
        if (oldSize != lastSize)
            console.log(`${lastSize}%`);
        oldSize = lastSize;
    });

    stream.pipe(writeStream);
    writeStream.on("finish", () => {
        console.log("Yazma tamamlandı...");
    });
});

yukarıdaki gibi yine başka bir örnek üzerinden gösterdiğim şekilde olayı ele alabiliriz.

Node.js - Stream Nedir? Nasıl Oluşturulur?

Bellek Performans Optimizasyonu

Şimdi ise streamlerin değerini daha iyi anlayabilmek için bellek performans optimizasyonunu yapacak ve elde ettiğimiz sonuçlarla durumu değerlendireceğiz.

const http = require("http");
const fs = require("fs");
const server = http.createServer((request, response) => {
    fs.readFile("text.txt", (error, data) => {
        if (error)
            throw error;

        response.end(data);
    });
});
server.listen(1453);

Yukarıdaki kod bloğunu incelerseniz eğer 1453 portunda bir server yayınlanmakta ve bu server içerisinde “text.txt”(1.975.000 KB) isimli dosya okunmaktadır. Öncelik olarak normal bir çalışmada performans durumunu gözlemleyebilmek için dikkat ederseniz eğer burada herhangi bir stream çalışması söz konusu değildir.

İlgili portu tarayıcıdan tetiklemeden önce “Task Manager” penceresinden “Performance” sekmesinde “Memory” istatistiklerini açmanızı öneririm.
Node.js - Stream Nedir? Nasıl Oluşturulur?

Yukarıdaki ekran görüntüsünü incelerseniz eğer %42’lik memory yoğunluğu portumuz tetiklendiği andan itibaren yapılan işlerin yükünden dolayı %100 gibi muazzam bir seviyeye ulaşmaktadır.

Şimdi aynı işi stream ile yaparken duruma göz atalım.

const http = require("http");
const fs = require("fs");
const stream = fs.createReadStream("text.txt");
const server = http.createServer((request, response) => {
    stream.pipe(response);
});
server.listen(1453);

Node.js - Stream Nedir? Nasıl Oluşturulur?
Görmüş olduğunuz gibi memory %100 gibi abartılı neticeler veren durumlara hiç meyletmemekte, stream ile okunan her bir chunk’ı işlemekte lakin memoryde tutarak biriktirmediği için yoğunluk bir şekilde kendini dengelemektedir.

Bu yapmış olduğumuz optimizasyon sayesinde de Stream’lerin performans açısından ne kadar hayati müdahalede bulunduğunu görmüş olduk.

Bol bol faydalanmanız dileğiyle…

Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar…

Bunlar da hoşunuza gidebilir...

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

*

Copy Protected by Chetan's WP-Copyprotect.