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:
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...
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...
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.
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...
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...
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...
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...