Gettickcount'a alternatif

Yazdığınız makaleleri ve üyelerimizin işine yarayacağını düşündüğünüz kodlarınızı gönderebilirsiniz. Bu foruma soru sormayın!
Cevapla
PROGRAMADOR
Üye
Mesajlar: 239
Kayıt: 04 Oca 2008 01:53
Konum: Karşıyaka/İzmir

Gettickcount'a alternatif

Mesaj gönderen PROGRAMADOR »

Merhaba arkadaşlar,

Bir sonsuz döngümüzün olduğunu düşünelim ve bu döngüde sürekli zamanı kontrol etmek için gettickcount fonksiyonunu kullandığımızı düşünelim. Bu sonsuz döngüde her saniye, 5 saniye, 10 saniye ve dakikada işlemler yapıldığını düşünelim. Gettickcount fonksiyonu böyle bir döngüde yavaşlamaya sebebiyet verecektir.

Gettickcount'a alternatif olarak aşağıdaki algoritmayı deneyebilirsiniz:

Kod: Tümünü seç

program GTT;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;

var
  zaman:cardinal;
  sayacsaniye,sayac5saniye,
  sayac10saniye,sayacdakika:cardinal;
  son_saniye:cardinal;
  son_5_saniye:cardinal;
  son_10_saniye:cardinal;
  son_1_dakika:cardinal;
  zaman_farki:integeR;

begin
  try
      zaman:=0;//zaman'ı sıfırdan başlatıyoruz.
      son_saniye:=0;//son saniye değerini sıfıra eşitliyoruz.
      sayacsaniye:=1; //saniye sayacını 1'e al.
      sayac5saniye:=1; //5 saniye sayacını 1'e al.
      sayac10saniye:=1; //10 saniye sayacını 1'e al.
      while True do begin
          zaman_farki:=zaman-son_saniye; //zaman ile son saniyenin farkını alıyoruz.
          if zaman_farki > 600000000 then begin //fark bir saniyeden büyükse
            son_saniye:=zaman;
            //her saniye yapılacaklar
            Writeln('Bu yazı saniyede bir çıkar');
            inc(sayacsaniye);
          end;
          if sayacsaniye>5 then begin  //beş saniye olduysa
             son_5_saniye:=zaman;
             //5 saniyede bir yapılacaklar
             Writeln('Bu yazı 5 saniyede bir çıkar');
             inc(sayac5saniye);
             sayacsaniye:=1;
          end;
          if sayac5Saniye>2 then begin //10 saniye olduysa
             son_10_saniye:=zaman;
             //10 saniyede bir yapılacaklar
             Writeln('Bu yazı 10 saniyede bir çıkar');
             inc(sayac10saniye);
             sayac5saniye:=1;
          end;
          if sayac10saniye>6 then begin //son bir dakika olduysa
             son_1_dakika:=zaman;
             //Dakikada bir yapılacaklar
             Writeln('Bu yazı dakikada bir çıkar');
             inc(sayacdakika);
             Sayac10saniye:=1;
             Zaman:=0;
             Son_saniye:=0;
             Continue;
          end;

          inc(zaman);
      end;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.
Ekleyeyim ki kodda zamanlar yaklaşık olarak hesaplanmıştır ve sistemin hızına göre de değişmektedir. Gerçi gettickcount fonksiyonu da çok yakın olsa da gerçek zaman değerini verememektedir.

İyi çalışmalar.
In dubio pro reo...
Şüpheden sanık/özgürlük yararlanır...
PROGRAMADOR
Üye
Mesajlar: 239
Kayıt: 04 Oca 2008 01:53
Konum: Karşıyaka/İzmir

Re: Gettickcount'a alternatif

Mesaj gönderen PROGRAMADOR »

Sadeleştilrilmiş hali aşağıdadır:

Kod: Tümünü seç


program GTT;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;

const
  Saniye = 600000000;
  Yarim_Saniye=Saniye/2;

var
  zaman:cardinal;
  sayacsaniye,sayac5saniye,
  sayac10saniye,sayacdakika:cardinal;
begin
  try
      zaman:=0;//zaman'ı sıfırdan başlatıyoruz.
      sayacsaniye:=1; //saniye sayacını 1'e al.
      sayac5saniye:=1; //5 saniye sayacını 1'e al.
      sayac10saniye:=1; //10 saniye sayacını 1'e al.
      while True do begin
          if zaman > Saniye then begin //saniyede bir
            //her saniye yapılacaklar
            Writeln('Bu yazı saniyede bir çıkar');
            inc(sayacsaniye);
            zaman:=0;
              if sayacsaniye>5 then begin //5 saniyede bir
                 //5 saniyede bir yapılacaklar
                 Writeln('Bu yazı 5 saniyede bir çıkar');
                 inc(sayac5saniye);
                 sayacsaniye:=1;
                    if sayac5saniye>2 then begin //10 saniyede bir
                       //10 saniyede bir yapılacaklar
                       Writeln('Bu yazı 10 saniyede bir çıkar');
                       inc(sayac10saniye);
                       sayac5saniye:=1;
                          if sayac10saniye>6 then begin //dakikada bir
                             //Dakikada bir yapılacaklar
                             Writeln('Bu yazı dakikada bir çıkar');
                             sayac10saniye:=1;
                          end;
                    end;
              end;
          end;
          inc(zaman);
      end;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.


In dubio pro reo...
Şüpheden sanık/özgürlük yararlanır...
Kullanıcı avatarı
SimaWB
Üye
Mesajlar: 1316
Kayıt: 07 May 2009 10:42
Konum: İstanbul
İletişim:

Re: Gettickcount'a alternatif

Mesaj gönderen SimaWB »

Programınızın While-True döngüsü içinde saniyede 600000000 defa girdiğini düşünerek bunu yapmışsınız ki bu hesap doğru olmaz maalesef. CPU'nun iş yüküne göre bu değer değişiklik gösterebilir.
Writeln'la ekrana mesaj yazdırdığınız andaki zamanı (milisaniyeyi de gösterecek şekilde) ekrana yazdırdığınız zaman bunu görebilirsiniz.
There's no place like 127.0.0.1
PROGRAMADOR
Üye
Mesajlar: 239
Kayıt: 04 Oca 2008 01:53
Konum: Karşıyaka/İzmir

Re: Gettickcount'a alternatif

Mesaj gönderen PROGRAMADOR »

Merhaba,
Evet haklısınız. Zaten yukarıda da hıza göre değişeceğini yazmıştım. Aslında benzer sorun gettickcount'ta da var ama hata payı daha az. Gettickcount ile geçen zaman hep kontrol edip farkı aldığımızda saniye, 5 saniye, 10 saniye ve dakikalık zaman dilimlerini yakalayabiliyoruz. Bu yakalama aşamalarında da sistemin çalışma hızı gene faktör oynayacaktır.

Google'da Gettickcount'a alternatif olan yolları araştırdım. Ancak hep api fonksiyonları ile alternatif yol arıyorlar.

Önerilerinizi bekliyorum.
In dubio pro reo...
Şüpheden sanık/özgürlük yararlanır...
PROGRAMADOR
Üye
Mesajlar: 239
Kayıt: 04 Oca 2008 01:53
Konum: Karşıyaka/İzmir

Re: Gettickcount'a alternatif

Mesaj gönderen PROGRAMADOR »

Aklıma harika bir fikir geldi.

Programın başında gettickcount ile bir kereye mahsus olmak üzere bir dakikada geçen döngü sayısını alırsam daha iyi bir sonuç alınacaktır.

Ancak sistem bazı zamanlarda hızlı, bazı zamanlarda yavaş olabilir. Bu durumda gene aksamalar olabilecektir.

İşten eve gittiğimde yeni kodları yazıp sizinle paylaşırım.
In dubio pro reo...
Şüpheden sanık/özgürlük yararlanır...
PROGRAMADOR
Üye
Mesajlar: 239
Kayıt: 04 Oca 2008 01:53
Konum: Karşıyaka/İzmir

Re: Gettickcount'a alternatif

Mesaj gönderen PROGRAMADOR »

Kodu şu şekilde yazdım:

Kod: Tümünü seç

program Project2;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  Windows;



var
  zaman:cardinal;
  sayacsaniye,sayac5saniye,
  sayac10saniye,sayacdakika:cardinal;
  tmp:cardinal;
  LC:cardinal;//loop count


  procedure SaniyedekiLoopSayisiniAl;
  var
    tc:cardinal;//tick count
    sonsaniye:cardinal;
  begin
    lc:=0;
    sonsaniye:=gettickcount;
    while true do begin
        tc:=gettickcount;
        if tc -sonsaniye> 1000 then exit;
        inc(lc);
    end;
  end;

begin
  SaniyedekiLoopSayisiniAl;


  try
      zaman:=0;//zaman'ı sıfırdan başlatıyoruz.
      sayacsaniye:=1; //saniye sayacını 1'e al.
      sayac5saniye:=1; //5 saniye sayacını 1'e al.
      sayac10saniye:=1; //10 saniye sayacını 1'e al.
      while True do begin
          if zaman > lc then begin //saniyede bir
            //her saniye yapılacaklar
            Writeln('Bu yazı saniyede bir çıkar');
            inc(sayacsaniye);
            zaman:=0;
              if sayacsaniye>5 then begin //5 saniyede bir
                 //5 saniyede bir yapılacaklar
                 Writeln('Bu yazı 5 saniyede bir çıkar');
                 inc(sayac5saniye);
                 sayacsaniye:=1;
                    if sayac5saniye>2 then begin //10 saniyede bir
                       //10 saniyede bir yapılacaklar
                       Writeln('Bu yazı 10 saniyede bir çıkar');
                       inc(sayac10saniye);
                       sayac5saniye:=1;
                          if sayac10saniye>6 then begin //dakikada bir
                             //Dakikada bir yapılacaklar
                             Writeln('Bu yazı dakikada bir çıkar');
                             sayac10saniye:=1;
                          end;
                    end;
              end;
          end;
          inc(zaman);
      end;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;

end.
Ancak nedense döngü hızlı çalışıyor. Nedenini bilen var mı?
In dubio pro reo...
Şüpheden sanık/özgürlük yararlanır...
Kullanıcı avatarı
SimaWB
Üye
Mesajlar: 1316
Kayıt: 07 May 2009 10:42
Konum: İstanbul
İletişim:

Re: Gettickcount'a alternatif

Mesaj gönderen SimaWB »

İşletim sisteminin timer fonksiyonları yerine alternatif aramak bence yanlış/gereksiz bir yol.
WaitForSingleObject'i araştırmanızı tavsiye ederim
There's no place like 127.0.0.1
PROGRAMADOR
Üye
Mesajlar: 239
Kayıt: 04 Oca 2008 01:53
Konum: Karşıyaka/İzmir

Re: Gettickcount'a alternatif

Mesaj gönderen PROGRAMADOR »

Tekrar merhaba,
Size kısmen katılıyorum. Ancak, beyin jimnastiği yaparak alternatif böyle bir çözüm ürettim.

Yaptığım testlerde döngü içinde Gettickcount fonksiyonunun çağrılması boş döngüyü üç kat yavaşlatıyor.

Aşağıdaki kodu inceleyelim:

Kod: Tümünü seç

program GTT;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,Winapi.Windows;

const
  Saniye = 600000000;
  Yarim_Saniye=Saniye/2;

var
  zaman:cardinal;
  sayacsaniye,sayac5saniye,
  sayac10saniye,
  sayacdakika,
  sayac15dakika,
  sayac30dakika:cardinal;
  LC:cardinal;//loop count

  procedure SaniyedekiLoopSayisiniAl;
  var
    tc:cardinal;//tick count
    sonsaniye:cardinal;
  begin
    lc:=0;
    sonsaniye:=gettickcount;
    while true do begin
        tc:=gettickcount;
        if tc -sonsaniye> 1000 then exit;
        inc(lc);
    end;
  end;

begin
  SaniyedekiLoopSayisiniAl;
  lc:=lc*3;
  try
      zaman:=0;//zaman'ı sıfırdan başlatıyoruz.
      sayacsaniye:=1; //saniye sayacını 1'e al.
      sayac5saniye:=1; //5 saniye sayacını 1'e al.
      sayac10saniye:=1; //10 saniye sayacını 1'e al.
      sayacdakika:=1;
      sayac15dakika:=1;
      sayac30dakika:=1;
      while True do begin
          if zaman > LC then begin //saniyede bir
            //her saniye yapılacaklar
            Writeln('Bu yazı saniyede bir çıkar');
            inc(sayacsaniye);
            zaman:=0; //saniye başı zamanı sıfırlıyoruz.
              if sayacsaniye>5 then begin //5 saniyede bir
                 //5 saniyede bir yapılacaklar
                 Writeln('Bu yazı 5 saniyede bir çıkar');
                 inc(sayac5saniye);
                 sayacsaniye:=1;
                    if sayac5saniye>2 then begin //10 saniyede bir
                       //10 saniyede bir yapılacaklar
                       Writeln('Bu yazı 10 saniyede bir çıkar');
                       inc(sayac10saniye);
                       sayac5saniye:=1;
                          if sayac10saniye>6 then begin //dakikada bir
                             //Dakikada bir yapılacaklar
                             Writeln('Bu yazı dakikada bir çıkar');
                             inc(sayacdakika);
                             sayac10saniye:=1;
                                if sayacdakika >15 then begin //15 dakiada bir
                                    //15 dakikada bir yapılacaklar
                                    Writeln('Bu yazı 15 dakikada bir çıkar');
                                    inc(sayac15dakika);
                                    sayacdakika:=1;
                                      if sayac15dakika >2 then begin //yarım saatte bir
                                          //15 dakikada bir yapılacaklar
                                          Writeln('Bu yazı yarım saatte bir çıkar');
                                          inc(sayac30dakika);
                                          sayac15dakika:=1;
                                            if sayac30dakika >2 then begin //saatte bir
                                                //15 dakikada bir yapılacaklar
                                                Writeln('Bu yazı yarım saatte bir çıkar');
                                                sayac30dakika:=1;
                                            end;
                                      end;
                                end;
                          end;
                    end;
              end;
          end;
          inc(zaman);
      end;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.
lc:=lc*3; satırı ile lc'yi üç katına çıkararak yaklaşık sonuç almaya çalıştım.

Ayrıca size sormak istediğim bir soru var: procedure SaniyedekiLoopSayisiniAl; ile bir saniye içindeki loop sayısını alırken thread mi kullanırsak daha iyi olur?
In dubio pro reo...
Şüpheden sanık/özgürlük yararlanır...
PROGRAMADOR
Üye
Mesajlar: 239
Kayıt: 04 Oca 2008 01:53
Konum: Karşıyaka/İzmir

Re: Gettickcount'a alternatif

Mesaj gönderen PROGRAMADOR »

Tekrar merhaba,

Sonunda sistemin hızına göre zamanı alan algoritmayı kodladım:

Kod: Tümünü seç


program GTT;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  Winapi.Windows;

var
  zaman:int64;
  sayacsaniye,sayac5saniye,
  sayac10saniye,
  sayacdakika,
  sayac15dakika,
  sayac30dakika:integer;
  LC:int64;//loop count
  ZamanKontrol:boolean;
  STime,ETime,Freq:int64;
  tmpLC:int64;

begin

  lc:=600000000; //varsayılan değer
  try
      zaman:=0;//zaman'ı sıfırdan başlatıyoruz.
      sayacsaniye:=1; //saniye sayacını 1'e al.
      sayac5saniye:=1; //5 saniye sayacını 1'e al.
      sayac10saniye:=1; //10 saniye sayacını 1'e al.
      sayacdakika:=1;
      sayac15dakika:=1;
      sayac30dakika:=1;
      tmpLC:=1;
      ZamanKontrol:=true;
      QueryPerformanceFrequency(Freq);

      while True do begin
          if zaman > LC then begin //saniyede bir
            //her saniye yapılacaklar
            Writeln(lc);
            if ZamanKontrol then begin
                if sayacsaniye=1 then QueryPerformanceCounter(STime);
                QueryPerformanceCounter(ETime);
                if (ETime-STime) div Freq=5 then begin
                      ZamanKontrol:=false;
                      lc:=tmplc div 5;
                end;
            end;
            inc(sayacsaniye);
            zaman:=0; //saniye başı zamanı sıfırlıyoruz.
              if sayacsaniye>5 then begin //5 saniyede bir
                 //5 saniyede bir yapılacaklar
                 Writeln('Bu yazı 5 saniyede bir çıkar');
                 inc(sayac5saniye);
                 sayacsaniye:=1;
                 {
                    if (ETime-STime) div Freq=5 then begin
                        ZamanKontrol:=false;
                        lc:=tmplc div 5;
                    end;  }
                    if sayac5saniye>2 then begin //10 saniyede bir
                       //10 saniyede bir yapılacaklar
                       Writeln('Bu yazı 10 saniyede bir çıkar');
                       inc(sayac10saniye);
                       sayac5saniye:=1;
                          if sayac10saniye>6 then begin //dakikada bir
                             //Dakikada bir yapılacaklar
                             Writeln('Bu yazı dakikada bir çıkar');
                             inc(sayacdakika);
                             sayac10saniye:=1;
                                if sayacdakika >15 then begin //15 dakiada bir
                                    //15 dakikada bir yapılacaklar
                                    Writeln('Bu yazı 15 dakikada bir çıkar');
                                    inc(sayac15dakika);
                                    sayacdakika:=1;
                                      if sayac15dakika >2 then begin //yarım saatte bir
                                          //15 dakikada bir yapılacaklar
                                          Writeln('Bu yazı yarım saatte bir çıkar');
                                          inc(sayac30dakika);
                                          sayac15dakika:=1;
                                            if sayac30dakika >2 then begin //saatte bir
                                                //15 dakikada bir yapılacaklar
                                                Writeln('Bu yazı yarım saatte bir çıkar');
                                                sayac30dakika:=1;
                                            end;
                                      end;
                                end;
                          end;
                    end;
              end;
          end;
          inc(zaman);
          if ZamanKontrol then inc(tmpLC);
      end;

  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

In dubio pro reo...
Şüpheden sanık/özgürlük yararlanır...
Cevapla