Forum: Projeler dkv RSS
Eşleme Tablosunu Kullanarak Kayıt Etmek
canalpay (Moderatör) #1
Kullanıcı başlığı: Can Alpay Çiftçi
Üye Tem 2009 tarihinden beri · 1133 mesaj · Konum: İzmir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Konu adı: Eşleme Tablosunu Kullanarak Kayıt Etmek
Şuan anladıklarım:
1. Anahtarlı bir biçimde verileri kaydedeceğiz. Örnek veri dosyası:
*-*deneme*-*
canalpayt
*-*den*-*
canalpayt

2. Bunu eşleme tablosuna aktarmak için şöyle bir kod kullanacağız(Bu eşleme tablosu olmadan ki kod.)):
    int veri_oku_eş(out dchar[][] okunanVeri_, dchar[] veriAdı_, dchar[]
                    veriYolu_, dchar[] anahtar_)
    {

        dchar[][] okunanVeri__;
        int bulundu = 0;
        string veriAdı_s = to!string(veriAdı_);
        veriAdı = veriAdı_s;///Classa eklenecek
        string veriYolu_s = to!string(veriYolu_);
        veriYolu = veriYolu_s;///Classa eklenecek
        string anahtar_s=to!string(anahtar_);
        anahtar = anahtar_s;///Classa eklenecek
        string dosyaAdı = veriYolu_s~"/"~veriAdı_s~".dkveş";
        string düzgünAnahtar = "*-*"~anahtar_s~"*-*"~"\n";
        File dosya = File(dosyaAdı,"r+");
        while (!dosya.eof()) {
            string satır = dosya.readln();
            if(satır==düzgünAnahtar || bulundu==1){
                if((satır[0..3]=="*-*")&&(satır!=düzgünAnahtar)){
                    bulundu=0;
                    break;
                }
                dstring satır_sd = to!dstring(satır);
                okunanVeri__~=satır_sd.dup;
            }
        }
        okunanVeri_=okunanVeri__;

        return 0;
}

3. Bu kod şu şekilde olacak -*-anahtar -*- sözcüğü okunduğunda eşlemetablosu[anahtar] olacak. Veriler okunduğunda da eşlemetablosu[anahtar]=veri olacak.


Bu eşleme tablosu neye yarayacak ? Bir veri dosyasını eşleme tablosuna aktaracağım ve 1'den fazla anahtarı erişirken daha hızlı erişeceğim.


Bu arada aklıma bir fikir geldi. mixin() sayesinde içinde yazanları derletebiliyorduk değil mi ?
Ben anahtarlı verileri şu şekilde kaydedeceğim(Yani veri dosyası şu olacak):
veri[anahtar]=bilgi;
Bunu dosyadan satır satır okuyup mixin ile derlemeye girmesini isteyeceğim. Bütün dosya otomatik eşlenecek ve ben sadece return veri[anahtar]
diyeceğim o veri döndürülecek. Değil mi ?
acehreli (Moderatör) #2
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4389 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
mixin() sayesinde içinde yazanları derletebiliyorduk değil mi ?
Ben anahtarlı verileri şu şekilde kaydedeceğim(Yani veri dosyası şu olacak):
veri[anahtar]=bilgi;
Bunu dosyadan satır satır okuyup mixin ile derlemeye girmesini isteyeceğim. Bütün dosya otomatik eşlenecek ve ben sadece return veri[anahtar]
diyeceğim o veri döndürülecek. Değil mi ?

Güzel bir fikir ama ancak verinin durağan olduğu programlarda işe yarar.

Bir oyun programının rekor listesini kaydetmek için kullandığı bir durumda, programı her başlatmadan önce derlemek gerekir. D çok hızlı derleniyor ama yine de garip. :)

Ali
canalpay (Moderatör) #3
Kullanıcı başlığı: Can Alpay Çiftçi
Üye Tem 2009 tarihinden beri · 1133 mesaj · Konum: İzmir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Siz bana nasıl yapacağıma dair bir örnek verebilir misiniz? (Kodlarla verirseniz iyi olur. Çünkü ben birbirimizi anlamadığımızı düşünüyorum.)

Bu arada mixin hakkında dedikleriniz doğru.(Ben yorumlamalı dillerle karıştırdım. )
acehreli (Moderatör) #4
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4389 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Sen soru cümlerinden sonra cevap da verince, ben sesli olarak düşünüyorsun ve neyi anlamış olduğunu söylüyorsun sanıyorum. Doğru olunca da cevap yazmanın gerektiğini düşünmüyorum. :)

Şu program bir eşleme tablosuna okuyor:

import std.cstream;
import std.stream;
import std.random;
 
void rastgele_yaz(string dosya_ismi)
{
    auto dosya = new File(dosya_ismi, FileMode.OutNew);
 
    foreach (i; 0 .. 10) {
        dosya.writefln("anahtar", i);
        dosya.writefln(uniform(0, 1000))// rastgele veri
    }
}
 
string[string] oku(string dosya_ismi)
{
    string[string] veriler;
 
    auto dosya = new File(dosya_ismi, FileMode.In);
 
    while (!dosya.eof()) {
        char[] anahtar = dosya.readLine();
 
        if (dosya.eof()) {
            throw new Exception(("Dosya düzeni hatası: "
                                 ~ anahtar ~ " için veri bulunamadı").idup);
        }
 
        char[] veri = dosya.readLine();
        veriler[anahtar] = veri.idup;
    }
 
    return veriler;
}
 
void main()
{
    string dosya_ismi = "deneme.txt";
    rastgele_yaz(dosya_ismi);
    string[string] veriler = oku(dosya_ismi);
 
    foreach (anahtar, veri; veriler) {
        dout.writefln(anahtar, ": ", veri);
    }
}

Eşleme tablosundan dosyaya yazmak da main'in sonunda dout'a yazdırmakla aynı olur. Aynı olsun diye ben stream.File'ı kullanmayı seviyorum.

Ali
canalpay (Moderatör) #5
Kullanıcı başlığı: Can Alpay Çiftçi
Üye Tem 2009 tarihinden beri · 1133 mesaj · Konum: İzmir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Tamam teşekkür ederim her şey anlaşıldı.

Şimdi sizin yazdığınız gibi işlevi kullanırsam eşleme tablosu hiç bir işe yaramıyor. Çünkü işlevi çağırdıkça işlev en baştan başlıyor.
En baştan başlatmaması için şöyle kodlamamız gerekiyor(Böylece 2.kere aynı veriyi okuyacaksa tanımlı olduğunu anlıyor ve 2.si çok daha hızlı çalışıyor.):

import std.cstream;
import std.stream;
import std.random;
import std.date;
 
void rastgele_yaz(string dosya_ismi)
{
    auto dosya = new File(dosya_ismi, FileMode.OutNew);
 
    foreach (i; 0 .. 100000) {
        dosya.writefln("anahtar", i);
        dosya.writefln(uniform(0, 1000))// rastgele veri
    }
}
 
string[string][string] oku(string dosya_ismi)
{
 
    string[string][string] veriler;
    if(veriler.length<1){
        auto dosya = new File(dosya_ismi, FileMode.In);
 
        while (!dosya.eof()) {
            char[] anahtar = dosya.readLine();
 
            if (dosya.eof()) {
                throw new Exception(("Dosya düzeni hatası: "
                                     ~ anahtar ~ " için veri bulunamadı").idup);
            }
 
            char[] veri = dosya.readLine();
            veriler[dosya_ismi][anahtar] = veri.idup;
        }
    }
    return veriler;
}
 
void main()
{
    string dosya_ismi = "deneme.txt";
    rastgele_yaz(dosya_ismi);
    void deneme(){
    string[string][string] veriler = oku(dosya_ismi);}
    void deneme2(){
    string[string][string] verileri = oku(dosya_ismi);
}
    dout.writefln("birinci: ", benchmark!(deneme)(1));
    dout.writefln("ikinci: ", benchmark!(deneme2)(1));
 
}

benchmark şablonunun verdiği sürelere inanmayın. İlki 1 dakika sürüyor hemen hemen 2.si 2 saniye filan. Ama benchmark'a göre 2side aynı hızda hemen hemen.


Ama şöyle bir sorun var gibi. Eşleme tablosuna aktardığımız zaman dosyaya yeni bir bilgi eklendiyse ne olacak. Sanırım bu durumda eski hali kalacak.

Ve yine ama bu kadar yüksek hız için o kadarcık külfet çekilir.
acehreli (Moderatör) #6
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4389 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
canalpay:
Şimdi sizin yazdığınız gibi işlevi kullanırsam eşleme tablosu hiç bir işe yaramıyor. Çünkü işlevi çağırdıkça işlev en baştan başlıyor.

Ben o işlevi bir dosyadan bir eşleme tablosuna nasıl okunacağını göstermek için yazdım. Bu soruyu sorduğunu düşündüğüm için... :)

Oysa şu kadar basit, değil mi:

//dosyadan okuduktan sonra
veriler[anahtar] = veri;

Doğrusu, o işlevi biraz da utanarak yazdım. :)

O işlevi her seferinde çağırmak istemedim. Yalnızca baştan, bir kere, çağrılacak ve bütün dosya belleğe alınacak. Ondan sonra bütün işlemler bellekte, bu veri tabanı ile yapılacak. Bir kere okunacak. php'cilerin istedikleri gibi... ;)

Eşleme tablosu, dkv'nin içindeki bir Tablo sınıfının üyesi olabilir (derlemeden):

class Tablo
{
    string[string] veriler;   // buna anahtarla erişilebilir
}
 
class dkv
{
    Tablo[string] tablolar;   // buna tablo ismiyle erişilebilir (dosya ismi
                              // fazla kullanışsız olabilir)
}
 
// Sonra dkv veriyi şöyle sunabilir:
string veri_oku(string tablo_ismi, string anahtar)
{
    return tablolar[tablo_ismi][anahtar];
}
 
// Veya kullanıcılar Tablo'yu doğrudan kullanabilirler:
Tablo tablo = benim_dkv.tabloya_eriş("benim-tablom");
string veri = tablo.veri_oku("benim-anahtarım");

string[string][string] oku(string dosya_ismi)
{
 
    string[string][string] veriler;

O yerel bir değişken değil mi? Yaşamına o noktada ve *boş* olarak başlar.

main içindeki veriler ile bunun bir ilgisi yok değil mi?

    if(veriler.length<1){

Hiç veriler.length'in >=1 olduğu durumla karşılaştın mı? Eğer öyleyse dmd bozuk demektir. ;)

Eşleme tablosuna aktardığımız zaman dosyaya yeni bir bilgi eklendiyse ne olacak.

Öncelikle: Senin tasarımını böyle bozduğum için kusura bakma. Öyle yapmak zorunda değilsin tabii ki. Seninki de çalışır. Ben yalnızca yavaş olabileceğini söylemek istedim.

Yanıt: Bütün işlemler bellekte yapılacak. Dosyaya yalnızca özellikle kaydet() dendiğinde, veya bu nesnenin sonlandırıcı işlevinde yazılacak.

Ama bu, benim kafamda canlandırdığım. Öyle yapmak zorunda değilsin. Bence önceki tasarımına dön, bu sınıf öyle kullanılsın ve varsa sorunlar yaşanarak görülsün. Eğer sorun yoksa, yoktur zaten... :)

Sanırım bu durumda eski hali kalacak.

Ve yine ama bu kadar yüksek hız için o kadarcık külfet çekilir.

Ona külfet değil, veri kaybı denir. :) Tabii ki kabul edilmez.

Ali
canalpay (Moderatör) #7
Kullanıcı başlığı: Can Alpay Çiftçi
Üye Tem 2009 tarihinden beri · 1133 mesaj · Konum: İzmir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
    string[string][string] oku(string dosya_ismi)
    {
    
        string[string][string] veriler;


O yerel bir değişken değil mi? Yaşamına o noktada ve *boş* olarak başlar.

Amacımız neydi ? Benim bildiğim kadarıyla eşleme tablosuna çağırıp oradan okutacağız. Böylece birden fazla kere çağrıldığında hız kazancı yaşayacağız.(Yani bunu yazmamdaki amaç daha önce okunup eşleme tablosuna aktarıldıysa yine aktarılmasın aktarılan eşleme tablosundan direk sonuca dönsün diyeyazdım.)


     if(veriler.length<1){


Hiç veriler.length'in >=1 olduğu durumla karşılaştın mı? Eğer öyleyse dmd bozuk demektir. ;)


Ben karşılaştım. Aynı işlevi 2.kez çağırdığımda zaten daha önceden tanımlı ve veriler aktarılmıştı.(Bence verilere bilgi aktarıldıktan sonra programın sonuna kadar o bilgileri tutması normal. Ne dmd'nin ne de benim hatam. ;-) Sadece verdiğim kodları derleyin ve kendiniz süre tutun. Ne demek istediğimi anlayacaksınız. ) O yüzden tekrar aktarılmadı.
Keşke derleyip çalıştırsaydınız, ne demek istediğimi anlardınız.
acehreli (Moderatör) #8
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4389 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
canalpay:
    string[string][string] oku(string dosya_ismi)
    {
    
        string[string][string] veriler;


O yerel bir değişken değil mi? Yaşamına o noktada ve *boş* olarak başlar.

Evet, o yerel bir değişken olduğu için; o noktada ve boş olarak oluşturulur.

Amacımız neydi ? Benim bildiğim kadarıyla eşleme tablosuna çağırıp oradan okutacağız.

Diğer tarafta da söylediğim gibi, ben baştan her bir tek veri için dosyayı açıp okuyorsun diye düşünmüştüm. O yüzden başından beri buna karşı çıkıyordum. Ama yanılmışım.

Ama, yukarıdaki oku işlevinde hiçbir kazancın olmuyor. İşlev her çağrıldığında yerel olduğu için, veriler diye yeni bir eşleme tablosu oluşturuluyor.

Böylece birden fazla kere çağrıldığında hız kazancı yaşayacağız.(Yani bunu yazmamdaki amaç daha önce okunup eşleme tablosuna aktarıldıysa yine aktarılmasın aktarılan eşleme tablosundan direk sonuca dönsün diyeyazdım.)

Yukarıdaki denetim hiçbir kazanç sağlamaz. length her zaman için 0'dır.

     if(veriler.length<1){


Hiç veriler.length'in >=1 olduğu durumla karşılaştın mı? Eğer öyleyse dmd bozuk demektir. ;)


Ben karşılaştım.

Dediğim gibi, bir hata olmalı. Ya dmd'de ya da başka bir nedenle öyle gördün.

Aynı işlevi 2.kez çağırdığımda zaten daha önceden tanımlı ve veriler aktarılmıştı.(Bence verilere bilgi aktarıldıktan sonra programın sonuna kadar o bilgileri tutması normal.

oku işlevini sen "bir_dosya" ile çağırdın ve veriler okundu. Sonra ben "baska_dosya" ile çağırdım. Senin verilerini mi göreceğimi düşünürsün?

Hem zaten istenmez, hem de öyle olmaz. veriler isimli nesne, yereldir, ve o anda boştur.

Sadece verdiğim kodları derleyin ve kendiniz süre tutun.

Bunu dün de yapmıştım, bugün de yaptım:

$ ./deneme
birinci: [3019]
ikinci: [2983]

Senin sonuçlarına benziyor mu? ;) Performans karşılaştırmalarının yanıltıcılığına hoş geldin! :)

Ne demek istediğimi anlayacaksınız. ) O yüzden tekrar aktarılmadı.

oku işlevine girince veriler içinde neler olduğuna bakman açıklayıcı olacak.

Keşke derleyip çalıştırsaydınız, ne demek istediğimi anlardınız.

Yanılmışsın. Dün de bugün de derledim ve denedim. :)

Senin birinci denemenin daha yavaş çıkmasının nedeni, herhalde dış etkenlerledir. Büyük olasılıkla dosya sistemi ile ilgili. Birinci sefer bütün dosya diskten belleğe aktarılıyor ve o yüzden sonraki çağrılar daha şanslı olarak bu giriş çıkış işlemini daha hızlı yaşıyorlar.

Ya da dmd'nin bir bozukluğudur. Ama yerel olan veriler ile ilgili değil.

Ali
canalpay (Moderatör) #9
Kullanıcı başlığı: Can Alpay Çiftçi
Üye Tem 2009 tarihinden beri · 1133 mesaj · Konum: İzmir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Tamamen siz haklısınız. Ben yapmak istediğim ile yaptığım şeyler ne yazıkki aynı değil.

Ama onu şu şekilde yaptığımı düşünün:
import std.cstream;
import std.stream;
import std.random;
import std.date;
string[string][string] veriler;
void rastgele_yaz(string dosya_ismi)
{
    auto dosya = new File(dosya_ismi, FileMode.OutNew);
 
    foreach (i; 0 .. 100000) {
        dosya.writefln("anahtar", i);
        dosya.writefln(uniform(0, 1000))// rastgele veri
    }
}
 
string[string][string] oku(string dosya_ismi)
{
 
 
    if(veriler.length<1){
        auto dosya = new File(dosya_ismi, FileMode.In);
 
        while (!dosya.eof()) {
            char[] anahtar = dosya.readLine();
 
            if (dosya.eof()) {
                throw new Exception(("Dosya düzeni hatası: "
                                     ~ anahtar ~ " için veri bulunamadı").idup);
            }
 
            char[] veri = dosya.readLine();
            veriler[dosya_ismi][anahtar] = veri.idup;
        }
    }
    return veriler;
}
 
void main()
{
    string dosya_ismi = "deneme.txt";
    rastgele_yaz(dosya_ismi);
    void deneme(){
    string[string][string] veriler = oku(dosya_ismi);}
    void deneme2(){
    string[string][string] verileri = oku(dosya_ismi);
}
    dout.writefln("birinci: ", benchmark!(deneme)(1));
    dout.writefln("ikinci: ", benchmark!(deneme2)(1));
 
}

Bu yapmak istediğime daha yakın sanırım. Birde siz deneyin.
acehreli (Moderatör) #10
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4389 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
canalpay:
string[string][string] veriler;

Anlaştık ama onun bir sınıfın bir üye nesnesi olması gerekiyor. Ya dkv'nin üyesi olmalı, ya da dkv'nin tablolar gibi bir üyesinin üyesi olmalı.

Global değişken kullanmak "mecbur kalmadıkça" yasak! :)

Ali
Doğrulama Kodu: VeriCode Lütfen resimde gördüğünüz doğrulama kodunu girin:
İfadeler: :-) ;-) :-D :-p :blush: :cool: :rolleyes: :huh: :-/ <_< :-( :'( :#: :scared: 8-( :nuts: :-O
Özel Karakterler:
Forum: Projeler dkv RSS
Bağlı değilsiniz. · Şifremi unuttum · ÜYELİK
This board is powered by the Unclassified NewsBoard software, 20100516-dev, © 2003-10 by Yves Goergen
Şu an: 2017-03-25, 14:40:04 (UTC -07:00)