Şimdiye kadar sgcWebSockets'teki her eşzamansız çağrı bir olay işleyicisi anlamına geliyordu. Arka plan iş parçacığında Get çağırıyordunuz, ya da Active := True ayarlayıp OnConnect olayını bekliyordunuz. Sonuç başka bir yerde, başka bir yöntemde geliyordu, dolayısıyla işlemi başlatan kod ile yanıtı tüketen kod farklı yerlerde yaşıyordu. Buna birincisine bağlı ikinci bir istek, artı hata işleme, artı yeniden gizlenmesi gereken bir "lütfen bekleyin" paneli ekleyin, sonunda formunuza yayılmış küçük bir durum makinesiyle baş başa kalırsınız: ne yaptığınızı hatırlamak için birkaç özel alan, son çağrının hâlâ devam edip etmediğini bilmek için bir bayrak ve üç istekten hangisinin geri döndüğünü anlamak zorunda olan bir işleyici.
sgcWebSockets 2026.7, bunun büyük kısmını ortadan kaldıran await tarzı bir API ekliyor. Bir HTTP isteği, bir WebSocket bağlantısı veya bir AI sohbet çağrısı artık bekleyebileceğiniz, geri çağrı zincirleyebileceğiniz veya iptal edebileceğiniz bir nesne döndürüyor, böylece kod gerçekleştiği sırada yukarıdan aşağıya okunuyor. İptal de göstermelik değil, yanıt sonunda geldiğinde onu yok saymak yerine altta yatan işlemi gerçekten durduruyor.
Görevler ve gelecekler
Yeni birim sgcBase_AsyncAwait. İki arayüz sunuyor. IsgcTask, biten ama bir değer üretmeyen işi temsil eder, IsgcFuture<T> ise T türünde bir değer üreten işi temsil eder. Her ikisi de size aynı dört şeyi verir: iş bitene kadar bloklamak için Await, başarılı olduğunda geri çağrı almak için ThenProc, bir istisna fırlattığında geri çağrı almak için OnError ve durdurmak için Cancel.
Kendinizinkini TsgcAsync.Run ile oluşturabilirsiniz. Geçirdiğiniz yordam veya fonksiyon bir arka plan iş parçacığında çalışır, geri çağrılar ise ana iş parçacığında döner, dolayısıyla ThenProc ve OnError içinde arayüze dokunmak güvenlidir.
uses
sgcBase_AsyncAwait;
begin
// the anonymous method runs on a background thread
TsgcAsync.Run<Integer>(
function: Integer
begin
Result := ExpensiveCalculation;
end)
.ThenProc(
procedure(const Value: Integer)
begin
// main thread, safe to update the UI
Label1.Caption := IntToStr(Value);
end)
.OnError(
procedure(E: Exception)
begin
// main thread as well
Label1.Caption := 'Failed: ' + E.Message;
end);
end;
Görev çalışırken kendini canlı tutar, dolayısıyla yukarıdaki gibi başlat ve unut tarzı bir çağrı sorunsuzdur. Daha sonra incelemek isterseniz, arayüzü bir değişkende tutun ve IsCompleted, IsCancelled ya da tsaPending, tsaRunning, tsaCompleted, tsaFailed veya tsaCancelled değerlerinden biri olan State özelliğini okuyun. Ayrıca bir zaman aşımından sonra tamamlanan ve tetiklenmeden önce iptal edilebilen bir görev döndüren TsgcAsync.Delay(aMilliseconds) ve bir arka plan görevinin içinden bir kod parçasını ana iş parçacığına geri iten TsgcAsync.RunOnMainThread da vardır.
Bir HTTP isteğini beklemek
HTTP istemcisi gelecekleri doğrudan açığa çıkarır, dolayısıyla çağrıyı kendiniz sarmalamanız gerekmez. GetFuture ve PostFuture, yanıt gövdesine çözümlenen bir IsgcFuture<string> döndürür.
uses
sgcHTTP_Client, sgcBase_AsyncAwait;
var
oHTTP: TsgcHTTPClient;
oFuture: IsgcFuture<string>;
begin
oHTTP := TsgcHTTPClient.Create(nil);
// the request runs on a background thread, this line returns immediately
oFuture := oHTTP.GetFuture('https://httpbin.org/get');
oFuture.ThenProc(
procedure(const Value: string)
begin
// main thread: Value is the response body
Memo1.Lines.Text := Value;
end)
.OnError(
procedure(E: Exception)
begin
ShowMessage('GET failed: ' + E.Message);
end);
end;
Zaten bir çalışan iş parçacığındaysanız ya da bir konsol uygulaması yazıyorsanız, basitçe bloklayıp değeri okuyabilirsiniz:
var
vBody: string;
begin
vBody := oHTTP.GetFuture('https://httpbin.org/get').Await;
WriteLn(vBody);
end;
Await, arka plan çağrısının fırlattığı her şeyi, özgün sınıf adını ve mesajı taşıyan bir EsgcAsyncException içinde sarmalayarak yeniden fırlatır, dolayısıyla etrafındaki düz bir try ... except yine çalışır. Gelecek iptal edilmişse, Await bunun yerine EsgcTaskCancelled fırlatır.
Bu yazıdaki her şeyden daha önemli bir uyarı. Ana iş parçacığında Await çağırmak ana iş parçacığını bloklar, bu da bir VCL veya FMX uygulamasında çağrı dönene kadar donmuş bir pencere demektir. Bir formda ThenProc kullanın. Await'i konsol uygulamaları, servisler ve zaten bir arka plan iş parçacığında çalışan kod için saklayın. HTTP istemcisinin kendisi iş parçacığı güvenli değildir, dolayısıyla eşzamanlı her isteğe tek bir örneği görevler arasında paylaşmak yerine kendi örneğini verin.
Bir WebSocket istemcisini bağlamak
Bağlanmak eskiden Active := True ayarlamak ve işe yaradığını söylemesi için OnConnect olayını, ya da yaramadığını söylemesi için OnError olayını beklemek anlamına geliyordu. ConnectTask size aynı şeyi bir görev olarak verir.
uses
sgcWebSocket, sgcBase_AsyncAwait;
var
oTask: IsgcTask;
begin
sgcWebSocketClient1.Host := 'echo.esegece.com';
sgcWebSocketClient1.Port := 443;
sgcWebSocketClient1.TLS := True;
oTask := sgcWebSocketClient1.ConnectTask(10000); // 10 second timeout
oTask.ThenProc(
procedure
begin
// main thread: the connection is established and ready to send
sgcWebSocketClient1.WriteData('hello');
end)
.OnError(
procedure(E: Exception)
begin
ShowMessage('Could not connect: ' + E.Message);
end);
end;
Bağlantı girişimi bir arka plan iş parçacığında çalışır ve zaman aşımı gerçek bir zaman aşımıdır. Süresi dolarsa görev askıda kalmak yerine başarısız olur. Görevi iptal etmek soketi keser, bu da hâlâ ağı bekleyen bir bağlantı girişiminin blokajını kaldırır.
Beklemeden bir bağlantıyı beklemek: Connect ve LastError
Her şeyin bir göreve ihtiyacı yoktur. Bazen sadece bağlanan ve işe yarayıp yaramadığını size söyleyen bir satır kod istersiniz, ki çoğu kişinin en başında Active := True ifadesinden beklediği şey de budur. 2026.7, yalnızca bağlantı gerçekten kurulduğunda, sadece başlatıldığında değil, dönen bloklayıcı bir Connect ekliyor.
var
vError: string;
begin
// returns True only when the WebSocket connection is fully established
if sgcWebSocketClient1.Connect(10000) then
sgcWebSocketClient1.WriteData('hello')
else
// find out why, without wiring an OnError handler
ShowMessage('Connect failed: ' + sgcWebSocketClient1.LastError);
// or get the reason back directly from the call
if not sgcWebSocketClient1.Connect(vError, 10000) then
ShowMessage('Connect failed: ' + vError);
// and a Disconnect that waits until the socket is really closed
sgcWebSocketClient1.Disconnect(5000);
end;
Bu, hızlı yeniden bağlanmalar sırasında eskiden ısıran bir yarış durumunu kapatır. Connect yalnızca bağlantı tamamen kurulduğunda True döndürdüğü için, artık hiçbir şey yarı hazır bir bağlantı üzerinde çalışmaz ve Disconnect dönmeden önce soketin gerçekten kapanmasını bekler, dolayısıyla bir yeniden bağlanma döngüsü önceki bağlantıyla çakışamaz. LastError bileşen üzerinde bulunur ve son girişimin başarısız olma nedenini tutar, böylece bir bağlantı girişiminin neden başarısız olduğunu herhangi bir olaya abone olmadan öğrenebilirsiniz. Her bağlantı girişiminin başında otomatik olarak temizlenir ve ClearLastError onu elle sıfırlar.
Connect'in, tıpkı Await gibi çağıran iş parçacığını blokladığını unutmayın. Onu bir çalışan iş parçacığından veya bir konsol uygulamasından kullanın, formdan ise ConnectTask kullanın.
Bir AI sohbetini beklemek
AI istemcisi aynı deseni izler. ChatAsync, istemi bir arka plan iş parçacığında gönderir ve model yanıtına çözümlenen bir IsgcFuture<string> döndürür, dolayısıyla bir formdaki sohbet çağrısı artık üç satır ve hiç olay işleyicisi değildir.
uses
sgcAI_Chat, sgcBase_AsyncAwait;
var
oFuture: IsgcFuture<string>;
begin
oFuture := sgcAIChat1.ChatAsync('Summarize this text in one sentence.');
oFuture.ThenProc(
procedure(const Value: string)
begin
// main thread: Value is the model answer
MemoAnswer.Lines.Text := Value;
ButtonSend.Enabled := True;
end)
.OnError(
procedure(E: Exception)
begin
MemoAnswer.Lines.Text := 'Error: ' + E.Message;
ButtonSend.Enabled := True;
end);
ButtonSend.Enabled := False; // the UI stays responsive while it runs
end;
O geleceği iptal etmek, devam eden isteği durdurur, dolayısıyla iletişim kutusunu kapatan veya Durdur'a basan bir kullanıcı, asla okumayacağı belirteçler için ödeme yapan bir LLM çağrısını arka planda çalışır durumda bırakmaz.
Bloklamak yerine zincirlemek (ThenProc / OnError)
Hangi iş parçacığının neyi çalıştırdığı konusunda açık olmakta fayda var, çünkü geri çağrı kodu genellikle orada yanlış gider. TsgcAsync.Run'a geçirdiğiniz iş ve GetFuture, ConnectTask veya ChatAsync arkasındaki istek, hepsi bir arka plan iş parçacığında çalışır. ThenProc ve OnError geri çağrıları ana iş parçacığına geri kuyruklanır, dolayısıyla içlerinde bir forma dokunmak güvenlidir.
İkisinden yalnızca biri tetiklenir. ThenProc işlem başarılı olduğunda çalışır, OnError bir istisna fırlattığında çalışır ve görev iptal edildiyse hiçbiri çalışmaz. Bu, sıralı durum için yeterlidir: bir sonraki çağrıyı önceki ThenProc içinden başlatın, zincir yürütüldüğü sırayla okunur. Zaten bir arka plan görevinin içindeyseniz ve yol boyunca arayüze dokunmanız gerekiyorsa, TsgcAsync.RunOnMainThread kullanın.
TsgcAsync.Run(
procedure
var
oHTTP: TsgcHTTPClient;
vBody: string;
begin
// background thread
oHTTP := TsgcHTTPClient.Create(nil);
try
TsgcAsync.RunOnMainThread(
procedure
begin
StatusBar1.SimpleText := 'Downloading...';
end);
vBody := oHTTP.Get('https://httpbin.org/get');
TsgcAsync.RunOnMainThread(
procedure
begin
// main thread again
Memo1.Lines.Text := vBody;
StatusBar1.SimpleText := 'Done';
end);
finally
oHTTP.Free;
end;
end);
Gerçekten iptal eden iptal
Çoğu "iptal" uygulaması bir bayrak ayarlar ve sonuç nihayet geldiğinde onu yok sayar. Soket açık kalır, istek çalışmaya devam eder ve iş parçacığı meşgul kalır. sgcWebSockets'te her eşzamansız çağrı göreve bir iptal eylemi kaydeder, dolayısıyla Cancel alttaki işleme ulaşır: bir HTTP geleceğini iptal etmek isteği durdurur, bir ConnectTask görevini iptal etmek soketi keser ve bir ChatAsync çağrısını iptal etmek AI çağrısını durdurur. Bloklanmış çalışan iş parçacığı, bir zaman aşımı dolana kadar orada oturmak yerine uyanır.
Bu da bir zaman aşımını bir Delay görevi ile bir iptalden inşa etmeyi kolaylaştırır, ki bu kütüphanede örnek 18 olarak gelen desendir:
var
oRequest: IsgcFuture<string>;
oTimeout: IsgcTask;
begin
oRequest := oHTTP.GetFuture('https://httpbin.org/delay/10');
oTimeout := TsgcAsync.Delay(3000);
// if the request answers first, drop the timeout
oRequest.ThenProc(
procedure(const Value: string)
begin
oTimeout.Cancel;
Memo1.Lines.Text := Value;
end);
// if the timeout fires first, abort the request for real
oTimeout.ThenProc(
procedure
begin
if not oRequest.IsCompleted then
begin
oRequest.Cancel;
ShowMessage('Request timed out');
end;
end);
end;
İptal edilmiş bir görev ne ThenProc ne de OnError tetikler. State değeri tsaCancelled olur, IsCancelled True döndürür ve Await içinde bloklanmış olan herkes bir EsgcTaskCancelled alır. Kendi görevinizi TsgcAsync.Run ile oluşturursanız ve bu görev durdurulabilir bir şeyi sarmalıyorsa, kendi durdurma işleminizi SetCancelProc ile kaydedin, Cancel onu çağıracaktır.
Delphi sürüm desteği
async/await birimi genel türler ve anonim yöntemler kullanır, dolayısıyla Delphi 2010 veya daha yenisini gerektirir. Delphi 7, 2007 ve 2009'da birim boş bir birim olarak derlenir ve eşzamansız yöntemler orada bulunmaz, dolayısıyla GetFuture, ConnectTask ve ChatAsync basitçe kullanılamaz. Kütüphanedeki diğer her şey, bu yöntemlerin yanında yer alan olay tabanlı API dâhil, Delphi 7'yi tam olarak eskisi gibi desteklemeye devam eder. Hiçbir şey kaldırılmadı ve mevcut hiçbir kodun davranışı değişmiyor, yeni çağrılar birer eklentidir.
Yukarıda anlatılan bloklayıcı Connect, Disconnect ve LastError genel tür kullanmaz, dolayısıyla desteklenen her Delphi sürümünde kullanılabilir.
Bütün bunlar için işlenmiş örnekler kaynakla birlikte sgcBase_AsyncAwait_Examples.pas içinde gelir, görevleri, gelecekleri, gecikmeleri, iptali, durumu yoklamayı, paralel HTTP isteklerini ve yukarıdaki zaman aşımı gözcüsünü kapsar.
Kullanılabilirlik
Görevler ve gelecekler, sgcWebSockets 2026.7'de Delphi 2010'dan Delphi 13'e kadar ve C++Builder'da, Win32/Win64, Linux64, macOS, Android ve iOS platformlarında kullanılabilir. Bloklayıcı Connect, Disconnect ve LastError ise Delphi 7'den 13'e kadar kullanılabilir.
Etkin aboneliği olan müşteriler yeni derlemeyi müşteri alanından indirebilir. Deneme kullanıcıları güncellenmiş kurulum dosyasını esegece.com/products/websockets/download adresinden alabilir.
Sorularınız, geri bildirimleriniz veya geri çağrı tabanlı bir formu görevlere taşımak için yardıma mı ihtiyacınız var? Bize ulaşın, kodu yazan kişilerden yanıt alacaksınız.
