AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Projekte AsyncCalls 2.91 - Asynchrone Funktionsaufrufe in Delphi
Thema durchsuchen
Ansicht
Themen-Optionen

AsyncCalls 2.91 - Asynchrone Funktionsaufrufe in Delphi

Ein Thema von jbg · begonnen am 15. Dez 2006 · letzter Beitrag vom 17. Mär 2009
Antwort Antwort
Seite 1 von 3  1 23      
jbg
Registriert seit: 12. Jun 2002
Mit meiner neuesten Erschaffung (AsyncCalls) kann man nun sehr leicht und ohne großen Aufwand mehreren Funktionen und Methoden zur gleichen Zeit ausführen und diese auch noch synchronisieren. Dazu ist nicht mehr notwendig, als eine der AsyncCall() Funktionen aufzurufen. Diese liefert dann ein IAsynCall Interface zurück mit dem der asynchrone Funktionsaufruf wieder synchronisiert werden kann. Da es sich um ein Interface handelt, wird beim Verlassen der Funktion/Methode auf alle noch ausstehenden asynchronen Funktionen gewartet.

Homepage, Download und Beschreibung

Beispielcode (Einlesen von drei Verzeichnissen in asynchronen Funktionen):
Delphi-Quellcode:
function TFormMain.DoSomething(Value: TObject): Integer;
begin
  Result := 0;
end;

procedure TFormMain.Button3Click(Sender: TObject);
var
  Value: Integer;
begin
  // TAsyncCalls.Invoke<TObject>(DoSomething, nil); wegen internal compiler error nicht mehr funktionsfähig

  TAsyncCalls.Invoke(procedure
  begin
    Value := 10;
    TAsyncCalls.VCLInvoke(procedure
    begin
      ShowMessage('Der Werk könnte ungleich 10 sein: ' + IntToStr(Value));
    end);
    Value := 20;
    TAsyncCalls.VCLSync(procedure
    begin
      ShowMessage('Der Wert ist 20: ' + IntToStr(Value));
    end);
    Value := 30;
  end).ForceDifferentThread;

  Sleep(1000);
end;
Delphi-Quellcode:
{ Die cdecl Funktion GetFiles() besitzt zwei Parameter vom Typ string und object, die hier ganz normal deklariert werden. }
procedure GetFiles(const Directory: string; Filenames: TStrings); cdecl;
var
  h: THandle;
  FindData: TWin32FindData;
begin
  h := FindFirstFile(PChar(Directory + '\*.*'), FindData);
  if h <> INVALID_HANDLE_VALUE then
  begin
    repeat
      if (StrComp(FindData.cFileName, '.') <> 0) and (StrComp(FindData.cFileName, '..') <> 0) then
      begin
        Filenames.Add(Directory + '\' + FindData.cFileName);
        if FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY <> 0 then
          GetFiles(Filenames[Filenames.Count - 1], Filenames);
      end;
    until not FindNextFile(h, FindData);
    Windows.FindClose(h);
  end;
end;

procedure TFormMain.ButtonGetFilesClick(Sender: TObject);
var
  Dir1, Dir2, Dir3: IAsyncCall;
  Dir1Files, Dir2Files, Dir3Files: TStrings;
begin
  Dir1Files := TStringList.Create;
  Dir2Files := TStringList.Create;
  Dir3Files := TStringList.Create;
  ButtonGetFiles.Enabled := False;
  try
    { Die beiden Parameter der GetFiles() Funktion werden mittels eines const array of const übergeben }
    Dir1 := AsyncCall(@GetFiles, ['C:\Windows', Dir1Files]);
    Dir2 := AsyncCall(@GetFiles, ['D:\Html', Dir2Files]);
    Dir3 := AsyncCall(@GetFiles, ['E:', Dir3Files]);

    { Warten bis die beiden asynchronen Funktion beenden sind. Während dieser Zeit dem die UI nicht einfrieren lassen }
    while AsyncMultiSync([Dir1, Dir2], True, 10) < 0 do
      Application.ProcessMessages;
    Dir3.Sync; // Auf die Beendigung der Dir3 Funktion warten

    MemoFiles.Lines.Assign(Dir1Files);
    MemoFiles.Lines.AddStrings(Dir2Files);
    MemoFiles.Lines.AddStrings(Dir3Files);
  finally
    ButtonGetFiles.Enabled := True;
    Dir3Files.Free;
    Dir2Files.Free;
    Dir1Files.Free;
  end;
end;
Angehängte Dateien
Dateityp: zip asynccalls_138.zip (32,2 KB, 46x aufgerufen)
 
Benutzerbild von Mavarik
Mavarik

 
Delphi 10.3 Rio
 
#2
  Alt 15. Dez 2006, 08:50
Hallo!

OK...

Du hast also eine Unit geschrieben, die eigene Threads erzeugt?

Kannst Du nochmal erklären, wofür und was das bringen soll?

Was ist mit dem Sync für Ausgaben? Was ist mit "Threadsave Code"?

Sorry, vielleicht brauche ich heute morgen auch nur erst mal einen Kaffee...

Grüsse Frank

PS.: Klingt aber spannend....
Frank Lauter
  Mit Zitat antworten Zitat
jbg

 
Delphi 10.1 Berlin Professional
 
#3
  Alt 15. Dez 2006, 13:13
Zitat von Mavarik:
Du hast also eine Unit geschrieben, die eigene Threads erzeugt?
Ja ich habe eine Unit geschrieben. Was verstehst du unter "eigene Threads erzeugen"? Natürlich nutzt AsynCalls Threads. Denn ansonsten würde die Asynchronität nicht funktionieren.

Zitat:
Kannst Du nochmal erklären, wofür und was das bringen soll?
Wenn man z.B. zwei Dateien downloaden und verarbeiten will kann man das wie folgt lösen:
Delphi-Quellcode:
DownloadFile('http://sonstwo.de/file1.html', Stream);
Verarbeite(Stream);
DownloadFile('http://sonstwo.de/file2.html', Stream2);
Verarbeite(Stream2);
Da das Netzwerk aber nicht besonders schnell ist, verbringt man eine ganze Menge an Zeit untätig wenn der erste Download ewig dauert, wobei der zweite recht schnell ist.

Mit AsyncCalls kann man das z.B so schreiben (wobei das sicherlich nicht der Weisheit letzter Schluss ist):
Delphi-Quellcode:
procedure DownloadFileAsync(const Url: string; Stream: TStream); cdecl;
begin
  DownloadFile(Url, Stream);
end;

for i := 0 to Urls.Count - 1 do
begin
  // beide Downloads starten
  a := AsyncCall(@DownloadFileAsync, [Urls[i], Streams[0]]);
  b := AsyncCall(@DownloadFileAsync, [Urls[i], Streams[1]]);

  Index := AsyncWaitSync([a, b], False); // warten bis mindestens ein AsyncCall beendet ist

  Verarbeite(Streams[Index]); // den ersten beendeten Download verarbeiten
  AsyncWaitSync([a, b], True); // auf den anderen Download warten
  Verarbeite(Streams[(Index + 1) mod 2]);
end;
Syntaktische Korrektheit ist nicht gegeben


Zitat:
Was ist mit dem Sync für Ausgaben?
Wenn du das Ergebnis einer async. Funktion benötigst, dann muss man einfach IAsyncCall.Sync aufrufen und bekommt das Ergebnis (sofern vorhanden => procedures haben einen undefinierten Rückgabewert)

Zitat:
Was ist mit "Threadsave Code"?
VCL Code sollte man nicht in einer async. Funktion aufrufen. Alle Arg-Parameter von AsyncCall() werden intern kopiert, womit sie in den async. Funktionen ohne bedenken benutzt werden können. Die Ausnahme bilden hier die AsynCallEx() Funktionen, die einen veränderbaren Record (Value Type) an die async. Funktion weiterleiten.
Delphi-Quellcode:
type
  TData = record
    s: string;
    i: Integer;
  end;

procedure DoSomething(var Data: TData);
begin
  Data.s := 'Hallo';
  Data.i := 10;
  Sleep(100); // ein wenig Zeit verplempern.
end;

var
  d: TData;
  a: IAsyncCall;
begin
  a := AsyncCallEx(@DoSomething, d);
  // irgendwas anderes machen ...
  a.Sync;
  ShowMessage(d.s + ': ' + IntToStr(d.i));
end;
Andreas aka AHUser aka jbg
  Mit Zitat antworten Zitat
Arthur Hoornweg

 
Delphi 2007 Professional
 
#4
  Alt 15. Dez 2006, 14:02
Eine Sache verstehe ich nicht (oder vielleicht sehe ich ein Problem
das es gar nicht gibt).

Du übergibst die Parameter als ein Array of Const.
Ich weiss nicht mit Sicherheit wie Delphi so ein Array verwaltet
(kopiert er etwa alles auf den Stack?) aber üblicherweise ist ein
"const" Parameter ein Pointer.

VAR x:tstringlist;
begin
x:=tstringlist.create;
x.add('test');
AsyncCall (@meinproc, [X]);
x.add('Hallo');



bekommt "meinproc" nun 1 oder 2 Strings zu verdauen?
Arthur Hoornweg
  Mit Zitat antworten Zitat
jbg

 
Delphi 10.1 Berlin Professional
 
#5
  Alt 15. Dez 2006, 19:39
Zitat von Arthur Hoornweg:
bekommt "meinproc" nun 1 oder 2 Strings zu verdauen?
Objekte werden natürlich nicht kopiert. Bei denen musst du dann schon selbst dafür sorgen, dass nicht zwei gleichzeitig darauf zugreifen. Das ist auch bei normalen Funktion der Fall. Was AsyncCall(func, []) anders macht, ist dass es elementare Typen (Char, Integer, ...) sowie Referenz-gehzählte Typen (String, Interface, ...) sicher macht (es wird intern eine Zuweisung an eine Variable des selben Types gemacht, der während des Funktionsaufrufs existent bleibt. Wenn du mehr erfahren willst, was da intern abläuft, dann solltest du einen Blick in die CopyVarRec() Funktion in AsyncCalls.pas werfen.

Zitat:
aber üblicherweise ist ein "const" Parameter ein Pointer.
Das ist er auch weiterhin. Nur zeigt der Zeiger halt nicht auf das Original, sondern auf eine interne Kopie.
Andreas aka AHUser aka jbg
  Mit Zitat antworten Zitat
jbg

 
Delphi 10.1 Berlin Professional
 
#6
  Alt 14. Aug 2007, 23:30
Da ich heute in einen schweren Bug gelaufen bin, der durch einen Bug in TThread.Resume ausgelöst wurde, habe ich die AsyncCalls Unit um einen Workaround aktualisiert.

Der Fehler äußert sich dahingehend, dass es beim Beenden der Anwendung auf ein bereits freigegebenes Thread-Objekt durch TThread.Resume (schreibend) zugegriffen wird.
Andreas aka AHUser aka jbg
  Mit Zitat antworten Zitat
blackdrake

 
Delphi 10.3 Rio
 
#7
  Alt 13. Aug 2008, 02:23
Wieso nennst du das synchron/asynchron? Wäre seriell/parallel nicht eine viel bessere Ausdrucksweiße?

Seriell ist das bearbeiten von Downloads nach und nach. Und Parallel ist das, was deine "ASync" Methodik macht.
Daniel Marschall
  Mit Zitat antworten Zitat
jbg

 
Delphi 10.1 Berlin Professional
 
#8
  Alt 27. Sep 2008, 15:47
Es gibt nun auch eine neue Version von AsyncCalls 2.9. Diese behebt einige Fehler und nutzt Generics und anonyme Methoden. Das Beispiel auf der ersten Seite habe ich aktualisiert.
Andreas aka AHUser aka jbg
  Mit Zitat antworten Zitat
Benutzerbild von Phoenix
Phoenix
 
#9
  Alt 27. Sep 2008, 16:02
Zitat von blackdrake:
Wieso nennst du das synchron/asynchron? Wäre seriell/parallel nicht eine viel bessere Ausdrucksweiße?
Naja.. in der Informatik ist es eigentlich so, das man hier tatsächlich von von synchron und asynchron redet. Das ist auch in anderen Sprachen so. Natürlich trifft die Beschreibung mit Seriell & Parallel den Kern der Sache genausogut (wenn nicht sogar besser), aber da sich Synchron/Asynchron inzwischen durchgesetzt hat ist es nur konsequent dabei zu bleiben. Damit weiss ein Informatiker halt, um was es sich hier dreht.
Sebastian Gingter
  Mit Zitat antworten Zitat
Benutzerbild von DeddyH
DeddyH

 
Delphi 12 Athens
 
#10
  Alt 27. Sep 2008, 18:04
Zitat von jbg:
Diese behebt einige Fehler und nutzt Generics und anonyme Methoden.
Das heißt, nur mit Delphi 2009 nutzbar?
Detlef
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 3  1 23      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:20 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz