Thread overview
Bir MmFile örneği
Feb 02, 2018
Salih Dinçer
January 27, 2018

MmFile, "memory-mapped file" anlamına geliyor. Türkçe'ye "bellekle eşleştirilmiş dosya" diye çevirebiliriz. Ne kadar büyük olursa olsun, bütün dosya sanki bellekte bir adreste oturuyormuş gibi sunuluyor. İşin güzel tarafı, aslında dosyanın yalnızca erişilen bölümleri gerektikçe otomatik olarak okunuyor.

Bu, aslında D'nin değil, işletim sisteminin sanal bellek (virtual memory) olanağından yararlanarak sunduğu bir olanak. Küçük dosyalarda yarardan çok zarar getirebilirmiş çünkü sanal belleğin kullandığı en küçük bellek birimi 4K. O yüzden, örneğin dosya 5K bile olsa toplamda 2 adet 4K kullanılması gerekiyor.

Bu olanak ancak binary dosyalarla kullanılabilir. Örneğin, bir metin dosyasını bu şekilde kullanmak uygun değil. Ek olarak, dosya içeriği olarak sunulan diziye eleman eklemeye kalkışmamak gerek çünkü D bütün içeriği bambaşka bir yere kopyalar ama işletim sisteminin bundan haberi olmaz.

Aşağıdaki program mevcut değilse bir dosya oluşturuyor, içeriğinin bir bölümünü dizi olarak kullanıyor. Güzel olan, dosyayı kendimiz açmıyoruz ve elemanları doğrudan kullanıyoruz. Programın gösterdiği gibi, dosyayı kayıt bile etmiyoruz. Biz belleği gerektiğinde dizi ile oynayarak değiştiriyoruz; asıl dosyanın değiştirilmesi işletim sistemine kalıyor.


import std.exception : enforce;
import std.range : iota, array;
import std.algorithm : map;
import std.string : format;
import std.conv : to;
import std.stdio : writefln, File, writeln;
import std.file : exists;
import std.mmfile : MmFile;

struct S {
   double d;
   int i;
   short s;
   byte b;
}

// Yanlışlıkla fazla büyük dosya üretmemek için yapay bir sınır
enum sınır = 1_000_000; // bayt olarak

void main() {
   const dosyaİsmi = "S_nesnelerim";

   if (exists(dosyaİsmi)) {
       writefln("%s dosyası mevcut olduğundan tekrar oluşturmuyorum.", dosyaİsmi);
   } else {
       const adet = 10;
       dosyaOluştur(dosyaİsmi, adet);
   }

   elemanlarıKullan(dosyaİsmi);
}

void dosyaOluştur(string dosyaİsmi, ulong adet) {
   enforce(adet * S.sizeof <= sınır,
           format("Fazla büyük dosya oluşturmak istemiyorum." ~
                  " Gerekiyorsa 'sınır' değişkeninin değerini değiştirin."));

   auto dosya = File(dosyaİsmi, "w");

   // Kaç adet eleman olduğunu yaz
   dosya.rawWrite([adet]);

   // Elemanları üret
   const dizi = adet.iota.map!(i => S(i + 0.5, i.to!int, i.to!short, i.to!byte)).array;

   // Dosyaya yaz
   dosya.rawWrite(dizi);

   writefln("%s dosyasını oluşturdum:", dosyaİsmi);
   writefln("%(%s\n%)", dizi);
}

void elemanlarıKullan(string dosyaİsmi) {
   // mm, dosyanın içeriğine erişim sağlayan bir nesnedir
   // 0: uzunluğunu dosyadan kendin hesapla anlamına geliyor
   // null: dosyayı bellekte istediğin yere yerleştir anlamına geliyor
   auto mm = new MmFile(dosyaİsmi, MmFile.Mode.readWrite, 0, null);

   // Bu dosya düzeninde en başta ulong türünde adet bilgisi bulunduğunu
   // biliyoruz.  O yüzden mm'in iki farklı dizi olarak dilimliyoruz:
   const adet = (cast(ulong[])(mm[0..ulong.sizeof]))[0];
   auto dizi = cast(S[])mm[ulong.sizeof..mm.length];

   // Elemanlara nasıl erişildiğini göstermiş olmak için ortadaki elemanla
   // oynuyoruz
   dizi[$/2].i *= 2;

   writefln("Ortadaki elemanı değiştirdim:");
   writefln("%(%s\n%)", dizi);
}

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

February 02, 2018

Yani 1 dosya içinde 10 adet S yapısını mı kopyaladık? Aynı şekilde biz bu bir deste S dizine erişip değiştikçe yaptığımız değişiklikler otomatik güncellenmiş mi olacak?

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

February 02, 2018

Alıntı (Salih Dinçer):

>

Yani 1 dosya içinde 10 adet S yapısını mı kopyaladık?

Eve ama hepsini birden yazma işi zaten rawWrite() ile hallediliyor.

Alıntı:

>

Aynı şekilde biz bu bir deste S dizine erişip değiştikçe yaptığımız değişiklikler otomatik güncellenmiş mi olacak?

Evet, kolaylık orada. Dosya sistemi dosyaları diskte ardışık olmayan parçalar halinde tutar. İşletim sisteminin burada yaptığı, bütün dosyayı tek bellek bloğu olarak göstermek ama yalnızca gereken parçalarını biz eriştikçe okumak ve yazmak.

Burada akla gelen bir soru, bellekteki her değişikliğin dosyayı hemen etkileyip etkilememesi. Çünkü eğer her değişiklik dosyaya yazıyorsa gereksiz yavaşlık oluşabilirdi. (Yani, sistemin "caching" davranışını merak ediyoruz.) Şimdi baktım, işletim sistemi sanal bellek için nasıl davranıyorsa MmFile da dolaylı olarak onu kullanıyormuş. Bundan oldukça etkin olduğunu anlamalıyız.

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]