Konuyu Oyla:
  • Derecelendirme: 0/5 - 0 oy
  • 1
  • 2
  • 3
  • 4
  • 5
Belli Periyotlarla Bir Metodun İşletilmesi
#1
Merhaba,
Daniele SpinettiYeniden Deneme Mekanizması konu başlıklı makalesinde işe yarar bir konuya değinmiş. 
Uygulamalarda sık kullanılan bir olayın denenmesi veya tekrar edilmesi için kullanılabilecek bir yöntem.
Örneğin, internet veya lokal network bağlantısına ihtiyaç duyan bir uygulamanın, bağlantıyı gerçekleştirmek için sürekli bağlanma isteği oluşturması. (Bağlantı deneme sayısı ve her denemede bekleme süresi belirlenebiliyor)
Paylaşmış olduğu örnekte, küçük bir değişiklik yaparak; farklı işlerde kullanılabilecek kodu paylaşmak istiyorum.
Daniele Spinetti'nin örneğinde, yapılan işlemin hataya düşmesi (işlemin başarısız olması) durumunda, belirlenen sayıda işlemin tekrarlanması isteniyor.
Şimdi vereceğim örnekte ise; TTimer çalışma prensibine benzer bir tekrarlama mekanizması işletiliyor. Tek farkı prosedürel metodun dinamik olmasıdır.
Her TTimer nesnesi yalnızca bir metod (OnTimer) işletir. Bu yöntemle her prosedürünüzü bir TTimer'a dönüştürebilirsiniz.

Unit
unit RetryHelperU;

interface

uses
 System.SysUtils;

type
 TRetryHelper = class(TObject)
   class procedure DoRetry(const ATimes: Integer; ADelayInMillis: Int64;
     AProc: TProc);
 end;

implementation

uses
 System.Classes;

{ TRetryer }

class procedure TRetryHelper.DoRetry(const ATimes: Integer;
 ADelayInMillis: Int64; AProc: TProc);
var
 LRetry: Integer;
begin
TThread.CreateAnonymousThread(
   procedure()
   begin
     LRetry := 0;
     while LRetry <= ATimes do
     begin
       Inc(LRetry);
       TThread.Queue(Nil,
         procedure
         begin
           AProc()
         end);
       if ADelayInMillis > 0 then
         TThread.Sleep(ADelayInMillis);
     end;
   end).Start;
end;

end.


Kullanımı
implementation

{$R *.fmx}

uses RetryHelperU;

procedure TForm1.Button1Click(Sender: TObject);
begin
 TRetryHelper.DoRetry(20, 750,
   procedure
   begin
     Form1.Edit2.Text := IntToStr(Edit2.Text.ToInteger + Edit1.Text.ToInteger);
   end);

end;

Untitled.gif
Cevapla
#2
İlgili kodda küçük bir eksiklik gözlemledim. Anonim bir thread'in içinde çağrılan AProc; kodunun TThread.Queue içinde çağrılması daha manidar olacaktır. Aksi taktirde, ilgili kod main thread haricinde çalışacağı için türlü türlü sorunlar ile karşılaşabilirsiniz. Thread'ler iyidir ama senkronize edilmeleri gerekir ;-)
Mal sahibi, mülk sahibi
Hani bunun ilk sahibi ?
Mal da yalan mülk de yalan
Var biraz da sen oyalan...
WWW
Cevapla
#3
(30-06-2017, Saat: 15:05)Tuğrul HELVACI Adlı Kullanıcıdan Alıntı: İlgili kodda küçük bir eksiklik gözlemledim. Anonim bir thread'in içinde çağrılan AProc; kodunun TThread.Queue içinde çağrılması daha manidar olacaktır. Aksi taktirde, ilgili kod main thread haricinde çalışacağı için türlü türlü sorunlar ile karşılaşabilirsiniz. Thread'ler iyidir ama senkronize edilmeleri gerekir ;-)

Düzeltme için teşekkür ederim hocam.
Aşağıdaki gibi mi olmalı? TProc tipindeki bir metodun doğrudan, Anonymous bir metod içerisinde kullanımında bir sakınca olur mu?
TThread.CreateAnonymousThread(
    procedure()
   begin
     LRetry := 0;
     while LRetry <= ATimes do
     begin
       Inc(LRetry);
       TThread.Queue(TThread.Current,
         procedure
         begin
           AProc()
         end);
       if ADelayInMillis > 0 then
         TThread.Sleep(ADelayInMillis);
     end;
   end).Start;
Cevapla
#4
TThread.Queue(nil, ...) biçiminde kullanmak daha iyi olur. Bu konu hakkında da bir yazı olacaktı forumda. TProc türünde bir metodun bir thread içinde kullanılması değil sorun üstadım. Asıl sorun, TProc türündeki metodun içinde ne yaptığınız ;-) VCL nesnelerine erişimde bulunuyorsanız ya da senkronize edilmesi gereken değişken ya da data'lara erişimde bulunuyorsanız bu durumda TThread.Queue ya da TThread.Synchronize kullanmanız icap eder.
Mal sahibi, mülk sahibi
Hani bunun ilk sahibi ?
Mal da yalan mülk de yalan
Var biraz da sen oyalan...
WWW
Cevapla
#5
(30-06-2017, Saat: 15:42)Tuğrul HELVACI Adlı Kullanıcıdan Alıntı: TThread.Queue(nil, ...) biçiminde kullanmak daha iyi olur. Bu konu hakkında da bir yazı olacaktı forumda. TProc türünde bir metodun bir thread içinde kullanılması değil sorun üstadım. Asıl sorun, TProc türündeki metodun içinde ne yaptığınız ;-) VCL nesnelerine erişimde bulunuyorsanız ya da senkronize edilmesi gereken değişken ya da data'lara erişimde bulunuyorsanız bu durumda TThread.Queue ya da TThread.Synchronize kullanmanız icap eder.

Değerli bilgiler için teşekkür ederim hocam.
Kodu belirttiğiniz şekilde düzeltiyorum.
Bu arada bahsetmiş olduğunuz ("...Bu konu hakkında da bir yazı olacaktı forumda...") konuyu Google'da arattırdım. Sonuç:

2017-06-30_16-01-31.png

Anahtar kelimemeye bakılırsa Google'daki DelphiCan iyi bir konumda.  Rolleyes
Cevapla
#6
Tavsiyeniz üzerine aşağıdaki gibi bir düzeltme yaptım. Teşekkür ederim Tuğrul hocam.
Thread medodunun eski hali:
  TThread.CreateAnonymousThread(
    procedure()
   begin
     LRetry := 0;
     while LRetry <= ATimes do
     begin
       Inc(LRetry);
       AProc();
       if ADelayInMillis > 0 then
         TThread.Sleep(ADelayInMillis);
     end;
   end).Start;

Thread medodunun yeni hali:
TThread.CreateAnonymousThread(
   procedure()
   begin
     LRetry := 0;
     while LRetry <= ATimes do
     begin
       Inc(LRetry);
       TThread.Queue(Nil,
         procedure
         begin
           AProc()
         end);
       if ADelayInMillis > 0 then
         TThread.Sleep(ADelayInMillis);
     end;
   end).Start;
Cevapla
#7
Rica ederim üstad.
Mal sahibi, mülk sahibi
Hani bunun ilk sahibi ?
Mal da yalan mülk de yalan
Var biraz da sen oyalan...
WWW
Cevapla
#8
Bu örnekte, TRetryHelper = class(TObject) sınıfının, TObject'ten türetilmesinin bir avantajı var mı?
Yoksa, bu tip işlemlerde (rutin olmayan bir çok metodun hiyerarşik olarak sınıflandırılarak, kullanılması) sınıf, temel sınıf (class) mı olmalıdır?
Kavram olarak bu metodolojiye Design Patterns mı deniyor?
Cevapla
#9
(01-07-2017, Saat: 10:29)Fesih ARSLAN Adlı Kullanıcıdan Alıntı: Bu örnekte, TRetryHelper = class(TObject) sınıfının, TObject'ten türetilmesinin bir avantajı var mı?
Yoksa, bu tip işlemlerde (rutin olmayan bir çok metodun hiyerarşik olarak sınıflandırılarak, kullanılması) sınıf, temel sınıf (class) mı olmalıdır?
Kavram olarak bu metodolojiye Design Patterns mı deniyor?

Üstad, sizin de malumunuz olduğu üzere TObject zaten en temel sınıf. TObject'ten türeyen herhangi bir sınıfın içinde implemente edilen metodlara ihtiyacınız yok ise, bu durumda o sınıflara da ihtiyacınız yok demektir. Tasarım Kalıpları ise ayrı bir hikaye. Kısaca tasarım kalıpları, yıllarca aynı problemler ile uğraşan programcıların izlediği yollardan en iyilerinin tespit edilip bu tespitin ön kabul haline getirilmesidir diyebiliriz. Tasarım Kalıplarını bilmek, benzer sorunlar ile karşılaştığınızda daha önce denenip, efektif bir çözüm olarak kabul edilen yolu izlemeniz anlamında size fayda sağlayabileceği gibi; birden fazla yazılımcının benzer bir problemi aynı kavramlar ile ifade edebilmesini de sağlamaktadır.

Delphi VCL içinde pek çok tasarım kalıbı kullanılmıştır.(Örneğin Observer) Ve yine Delphi'de projenize Model View özelliği kazandırdığınızda, Delphi sizin için tasarım kalıplarına örnek kodlar da oluşturabilmektedir.
Mal sahibi, mülk sahibi
Hani bunun ilk sahibi ?
Mal da yalan mülk de yalan
Var biraz da sen oyalan...
WWW
Cevapla
#10
Emeğinize sağlık çok güzel ve kullanışlı olmuş. Bende örneğinizi  denemek isteyenlere ufak bir hatırlatma yapayım.  Örnekte LRetry := 0; değerini 1 yaparak kullanın. Aksi taktirde 5 defa yaptırmak istediğiniz bir işlemden 6 defalık sonuç alabilir ben gibi şaşırabilirsiniz Smile Sebebi saymaya her zaman ki gibi sıfırdan saymaya başlaması. Bu arada incelerken yeni birşey daha öğrenmiş oldum. AProc: TProc kullanarak  prosedüre, prosedürü değişken olarak verilebildiğini öğrenmekte güzel oldu.Teşekkürler
Cevapla




Konuyu Okuyanlar: 1 Ziyaretçi