Laden...

Asynchrone Methoden für synchrone Methoden bauen

Erstellt von Maaka vor 14 Jahren Letzter Beitrag vor 14 Jahren 8.771 Views
Maaka Themenstarter:in
21 Beiträge seit 2010
vor 14 Jahren
Asynchrone Methoden für synchrone Methoden bauen

Hi,

habe mir eine kostenlose FTP-Bibliothek heruntergeladen, jedoch hat diese keine asynchronen Methoden. Also hängt alles immer etwas wenn ich da was machen will.
Also habe ich versucht dafür asynchrone Methoden zu bauen.
Jedoch hänge ich da nun etwas fest.

Hab es mal mir der FTPClient.Dir() Methode versucht die 3 Überladungen aht:
FTPClient.Dir();
FTPClient.Dir( string pathName );
FTPClient.Dir( string pathName, bool full );

Hab zwar (denke ich?) das aufrufen hinbekommen, jedoch habe ich nun keine Idee wie ich bei der .EndDir(); Methode das Ergebniss von dDir bekomme.

Auch denke ich nicht das so wie ich es versucht habe der beste Weg ist, gibt es da bessere Wege? Habe versucht das verhalten von TcpClient.BeginAcceptTcpClient/EndAcceptTcpClient nachzubauen.

Auch weiß ich nicht genau wie ich das mit Überladungen hinbekommen soll, also habe ich es mal versucht, aber denke da gibts auch eine bessere Möglichkeit...

(Habe auch mal auf MSDN und so geguckt aber kein Beispiel zum Verhalten von TcpClient.BeginAcceptTcpClient/EndAcceptTcpClient gefunden, und auch nicht zu ähnlichem)


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Windows.Forms;
using System.IO;
using System.Threading;
using System.Collections;
using EnterpriseDT.Net.Ftp;

namespace FTPLinker
{
   
   class FTP
   {
      
      FTPClient myFTP = null;

      public delegate void delT_Dir(string dir = null, bool? full=null);
      delT_Dir del_Dir;

      public bool IsConnected
      {
         get
         {
            return myFTP.IsConnected;
         }
      }

      public string[] Dir( string dir )
      {
         return dDir( dir );
      }

      public string[] Dir()
      {
         return dDir();
      }

      public string[] Dir( string dir, bool full )
      {
         return dDir( dir, full );
      }

      private string[] dDir( string dir = null, bool? full = null )
      {
         if( dir == null )
         {
            return myFTP.Dir();
         }
         else if( full == null )
         {
            return myFTP.Dir( dir );
         }
         bool nfull = full ?? false;
         return myFTP.Dir( dir, nfull );

      }

      public IAsyncResult BeginDir( AsyncCallback requestCallback, object state )
      {
         return del_Dir.BeginInvoke( null, null, requestCallback, state );
      }

      public IAsyncResult BeginDir( string dirName, AsyncCallback requestCallback, object state )
      {
         return del_Dir.BeginInvoke( dirName, null, requestCallback, state );
      }

      public IAsyncResult BeginDir( string dirName, bool full, AsyncCallback requestCallback, object state )
      {
         return del_Dir.BeginInvoke( dirName, full, requestCallback, state );
      }

      public string[] EndDir( IAsyncResult ar )
      {
         
      }

      public FTP()
      {
         del_Dir = new delT_Dir(dDir)
         myFTP = new FTPClient();
         myFTP.ConnectMode = FTPConnectMode.PASV;
         myFTP.ActiveIPAddress = System.Net.Dns.GetHostAddresses( "ftp.national-anime.com" )[ 0 ];

      }
   }
}

925 Beiträge seit 2004
vor 14 Jahren

Da würde ich mal das Stichwort BackgroundWorker in den Raum werfen.

998 Beiträge seit 2007
vor 14 Jahren

public string[] EndDir( IAsyncResult ar )
      {
            return del_Dir(ar);
      }

tuts auch schon 😉

Lg David

49.485 Beiträge seit 2005
vor 14 Jahren

Hallo Maaka,

Auch denke ich nicht das so wie ich es versucht habe der beste Weg ist, gibt es da bessere Wege?

die von Microsoft empfohlen Vorgehensweise für die Implementierung asynchroner Methoden findest du in Entwurfsmuster für die asynchrone Programmierung. Mir gefällt das allerdings nicht: zu kompliziert, zu spezifisch, zu unflexibel.

Ich verwende am liebsten die Thread-Klasse. Ob man stattdessen den schon genannten BackgroundWorker nimmt, ist überwiegend Geschmackssache. Manche im Forum empfehlen nicht direkt Threads, sondern besser Threadpool verwenden. Letzteres ist in meinen Augen allerdings nur relevant, wenn viele Threads erzeugen würde, die immer nur sehr kurz leben.

3.971 Beiträge seit 2006
vor 14 Jahren

Bei der BeginXYZ-Methode gibst du eine eigene Instanz von IAsyncResult zurück. An diese Klasse kannst du beispielsweise den Rückgabewert von der XYZ hängen (genauso wie die IAsyncResult-Instanz von Delegate.BeginInvoke). In EndXYZ einfach den Wert auslesen (vorher mit WaitHandle.WaitOne allerdings auf die Fertigstellung warten!) und zurückgeben.

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...

5.299 Beiträge seit 2008
vor 14 Jahren

Hi,

habe mir eine kostenlose FTP-Bibliothek heruntergeladen, jedoch hat diese keine asynchronen Methoden. Also hängt alles immer etwas wenn ich da was machen will.
Also habe ich versucht dafür asynchrone Methoden zu bauen.

In gewisser Weise habe ich das in [ExtensionMethods] CrossThread-Calls auch getan, nur gleich generisch.

Etwas weiter gefasst habichs neulich nochmal hier eingestellt: AsyncWorker - CodeProject

Dort lasse ich mich auch etwas dazu aus, dasses beim threading prinzipiell keine Return-Values geben kann, weil der Return-Punkt bei Parallel-Verarbeitung ja längst durchgelaufen ist - man muß also umdesignen.

Backgroundworker würdich nicht so empfehlen, da müsstest du ja für jede Methode deiner Lib einen BackgroundWorker erstellen. V.a. aber wg. der umständlichen untypisierten Parameter-Übergabe an die Worker-Methode.

Der frühe Apfel fängt den Wurm.

Maaka Themenstarter:in
21 Beiträge seit 2010
vor 14 Jahren

Dort lasse ich mich auch etwas dazu aus, dasses beim threading prinzipiell keine Return-Values geben kann, weil der Return-Punkt bei Parallel-Verarbeitung ja längst durchgelaufen ist - man muß also umdesignen.

Hi, muss ich mir noch näher ansehen (die Links), aber ja. Die Begin Methode gibt ja nichts zurück (außer das IAsyncResult), die End Methode gibt aber etwas zurück (z.b. TcpClient bei TcpListener.EndAcceptTcpClient).

die von Microsoft empfohlen Vorgehensweise für die Implementierung asynchroner Methoden findest du in
>
. Mir gefällt das allerdings nicht: zu kompliziert, zu spezifisch, zu unflexibel.

Naja ich dachte mir halt wenn es in .Net schon so gemacht ist und ich gewöhnt bin es so zu benutzen, könnte ich es ja auch gleich so machen wie in .Net ^^

Bei der BeginXYZ-Methode gibst du eine eigene Instanz von IAsyncResult zurück. An diese Klasse kannst du beispielsweise den Rückgabewert von der XYZ hängen (genauso wie die IAsyncResult-Instanz von Delegate.BeginInvoke). In EndXYZ einfach den Wert auslesen (vorher mit WaitHandle.WaitOne allerdings auf die Fertigstellung warten!) und zurückgeben.

Ah.. .ja habe nicht verstanden wie ich den Rückgabewert einbringen soll x.x aber grade gesehen das ich beim Delegat void genommen habe statt string[] deswegen hat .EndInvoke auch nur void zurückgegeben....

Also problem wohl gelöst, außer das ich mir immer noch nicht sicher bin ob das so gut ist wie ich das mit den Überladungen gemacht habe

5.299 Beiträge seit 2008
vor 14 Jahren

Die Begin Methode gibt ja nichts zurück (außer das IAsyncResult), die End Methode gibt aber etwas zurück (z.b. TcpClient bei TcpListener.EndAcceptTcpClient).

Naja, das mitte Begin und End - Methode ist ja nur ein Drumrum-gemurkel um die Tatsache, dass eine Ergebnis-_Rückgabe _nicht möglich ist, sondern nur eine Weiterleitung.
Die Ergebnisse des Nebenthreads werden ja nicht an TcpListener.BeginAcceptTcpClient zurückgegeben, sondern an TcpListener.EndAcceptTcpClient weitergeleitet.

Der frühe Apfel fängt den Wurm.

Maaka Themenstarter:in
21 Beiträge seit 2010
vor 14 Jahren

Ja aber so will ich das ja. Im Callback ruf ich dann die .End Methode auf und gut ist 😄

49.485 Beiträge seit 2005
vor 14 Jahren

Hallo Maaka,

und wann ruft man die End-Methode auf? Das ist doch das Problem. Ruft man sie sofort auf, kann man sich den Aufwand sparen, weil man dann wieder synchron arbeitet. Und wenn man sie nicht sofort aufruft, wann dann? Woher weiß man, dass die asynchrone Verarbeitung beendet ist?

Entweder man verwendet Events, dann braucht man aber weder ein IAsyncResult noch eine End-Methode oder man macht die Methoden eben gar nicht asynchron, sondern überlässt es dem Verwender, die synchronen Methoden mittels einen Threads/BackgroundWorkers asynchron zu anderen Threads, aber eben innerhalb des Threads synchron auszuführen, weshalb es auch kein Problem mit den Rückgabewert gibt.

Hallo ErfinderDesRades,

Backgroundworker würdich nicht so empfehlen, da müsstest du ja für jede Methode deiner Lib einen BackgroundWorker erstellen.

nein, nicht die Lib sollte asynchron arbeiten, sondern es sollte dem Verwender der Lib überlassen werden, ob er die Methoden aus einem Thread heraus aufrufen will oder nicht. Dabei wird der Verwender natürlich nicht für jede Methode einen Thread erzeugen, sondern in einem Thread (und vermutlich sogar in einer Schleife) so viele Methoden aufrufen, wie es nötig ist. Das ist für den Verwender aus den o.g. Gründen einfacher als mit asynchronen Begin-/End-Methoden zu arbeiten.

herbivore

M
1.439 Beiträge seit 2005
vor 14 Jahren

Hallo herbivore,

typischerweise ruft man die EndXXX Methode im Callback, dem man der BeginXXX übergibt, auf.
Denn das ist ja genau das, was man will: Wenn die Operation zu Ende ist, führe Code - wie nächste Operation starten, oder Label in der GUI aktualisieren aus.
Und dieses Pattern lässt sich leicht und effizient mit Callbacks lösen.

F
10.010 Beiträge seit 2004
vor 14 Jahren

Du hast nicht gelesen was herbivore geschrieben hat.

Wenn du sowieso mit einem Callback arbeitest, brauchst du keine Asynchronen Methoden.

M
1.439 Beiträge seit 2005
vor 14 Jahren

Doch habe ich. Ich habe mich auf

und wann ruft man die End-Methode auf? Das ist doch das Problem. Ruft man sie sofort auf, kann man sich den Aufwand sparen, weil man dann wieder synchron arbeitet. Und wenn man sie nicht sofort aufruft, wann dann? Woher weiß man, dass die asynchrone Verarbeitung beendet ist?

bezogen.

Wenn du sowieso mit einem Callback arbeitest, brauchst du keine Asynchronen Methoden.

Ich würde eher sagen: damit ich mit einem Callback arbeiten kann brauche ich asynchrone Methoden

Maaka Themenstarter:in
21 Beiträge seit 2010
vor 14 Jahren

Du hast nicht gelesen was herbivore geschrieben hat.

Wenn du sowieso mit einem Callback arbeitest, brauchst du keine Asynchronen Methoden.

Naja ohne Asynchrone würde es ja hängen... mit denen hängt es nicht

F
10.010 Beiträge seit 2004
vor 14 Jahren

Häh?

Irgendwie drehen wir uns hier im Kreis.

Wenn du mit Callbacks arbeitest, benötigst du keine Asynchrone herangehensweise ( wie sie oben beschrieben ist) , sondern du kannst ganz normal mit Threads oder dem BGW arbeiten.

Die oben beschriebene Herangehensweise ist dafür viel zu umständlich und Fehleranfällig.
Das ist es was herbivore schrieb, und ich nochmal unterstreichen wollte.

Maaka Themenstarter:in
21 Beiträge seit 2010
vor 14 Jahren

Naja, mit Threads/BGW find ich es auch umständlich... sogar noch umständlicher eigentlich.
So hab ich einfach die normale Methode zum ausführen. Dann eine Begin/End Methode, Callback übernimmt es eh selbst und mit der. End Methode gibts etwas zurück. Ich könnte nun auch .End weglassen aber dann müsste ich mich entweder selsbt um den Callback kümmern und/oder sogar einen eigenen Callback-Typ anlegen?

Zumindest kenne ich keinen guten Weg

5.299 Beiträge seit 2008
vor 14 Jahren

also die Vorgehensweise mit Begin/End am Beispiel AcceptTCPClient:

  1. TcpListenerInstance.BeginAcceptClient(arguments, CallBack, TcpListenerInstance);
  2. Callback implementieren
  3. im Callback aus dem IASyncResult.State die TcpListenerInstance wieder herausholen, TcpListenerInstance.EndAcceptClient() aufrufen
  4. mit Control.Invoke eine Methode "NotifyGui" aufrufen, um im Gui anzuzeigen, dass ein Client hinzugekommen ist.
  5. NotifyGui() implementieren

ist doch ziemlich verkorkst, odr? Schon, dass man TcpListenerInstance als Parameter seiner eigenen ObjektMethode mitgeben muß - ziemlich unintuitiv, findich.

Mit CrossThread / AsyncWorker

  1. eine Methode "WorkAsync" implementieren, die den auszulagernden Job erledigt. Wenn der Job erledigt, noch innerhalb von WorkAsync "NotifyGui" aufrufen, um die Erledigung anzuzeigen.
  2. NotifyGui() implementieren

WorkAsync kann Parameter typisiert empfangen, so wie sie gebraucht werden, ebenso NotifyGui (Die Methoden sollten im Einzelfall übrigens spezifischer heißen)

Jo, und CrossThread bzw. AsyncWorker gibt die Möglichkeit, WorkAsync im Nebenthread aufzurufen, mit den erf. typisierten Paremetern, und andersrum NotifyGui im Gui-Thread aufzurufen, ebenfalls ordentlich parametrisiert.

Dabei hat der Asyncworker noch ein Event im GuiThread, wo man das Gui anpassen kann (Buttons enablen/disablen etc.), und Mechanismen, um Cancelation und ProgressReporting zu unterstützen.

Der frühe Apfel fängt den Wurm.

Maaka Themenstarter:in
21 Beiträge seit 2010
vor 14 Jahren

Hm, also bei mir klappt es eigentlich auch wenn ich den Callback nicht als static habe, dann brauch ich auch keine Instanz von TcpListener übergeben?

Naja ich probier mal Asyncworker aus

M
1.439 Beiträge seit 2005
vor 14 Jahren

Irgendwie drehen wir uns hier im Kreis.
Wenn du mit Callbacks arbeitest, benötigst du keine Asynchrone herangehensweise ( wie sie oben beschrieben ist) , sondern du kannst ganz normal mit Threads oder dem BGW arbeiten.

Ich rede hier von callbacks im Sinne von AsyncCallback. Und für diese braucht man nun mal asynchrone Methoden. Aber vielleicht kannst du ja erklären was du unter callbacks versteht.

@ErfinderDesRades
Dein Beispiel ist aber sehr an den Haaren herbeigezogen. Hier eine einfache Implementierung mit async IO. Was soll daran verkorkst oder kompliziert sein. Abgesehen davon funktioniert diese Lösung auch in multithreaded Anwendungen ohne GUI.


private TcpListener listener;

public Form1() {
    ...
    listener.BeginAcceptTcpClient(OnClientConnected, null);
}

private void OnClientConnected(IAsyncResult ar) {
    TcpClient client = listener.EndAcceptTcpClient(ar);

    Invoke(...);
}

Maaka Themenstarter:in
21 Beiträge seit 2010
vor 14 Jahren

Ja, so mache ich das auch. Objekte übergebe ich dann nur wenn ich z.B. Information brauche wie ich das im Callback verarbeiten soll.

5.299 Beiträge seit 2008
vor 14 Jahren

@ErfinderDesRades
Dein Beispiel ist aber sehr an den Haaren herbeigezogen.

Jo, ich fürchte, du hast recht. Grad bei TCP kommt man mit Begin/End recht gut klar, weil man ja gar keine eigenen Berechnungen o. dgl. anstellt, und auch gar keine Parameter braucht.

In VersuchsChat brauch ich die CrossThreads auch nur für die Transferierung asynchron empfangener Messages in den GuiThread, und mach ansonsten auch mit Begin/End.

Der frühe Apfel fängt den Wurm.

49.485 Beiträge seit 2005
vor 14 Jahren

Hallo marsgk,

das mit den Callbacks hatte ich verdrängt, weil ich das "Entwurfsmuster für die asynchrone Programmierung" nicht mag und deshalb nicht benutze.

Sicher, mit den Callbacks hat man den richtigen Zeitpunkt. Aber dadurch wird das Muster in meinen Augen nicht besser. Es wird asynchron auf der Ebene einzelner Methoden gearbeitet. Das ist einfach unpraktisch.

Zum einen kann es sein, dass nicht die einzelne Methode langlaufend ist, sondern erst das Zusammenspiel vieler Methoden oder der Aufruf einer Methode in einer Schleife. Dann nützt einem das Muster nichts.

Zum zweiten könnte es sein, dass man mehrere (asynchrone) Methoden hintereinander ausführen möchte. Dann bekommt man eine Art (End-)Rekursion (also aus dem Callback die nächste Methode aufrufen, die wieder einen Callback aufruf, ...) und bekommt damit möglicherweise einen StackOverflow. Und selbst wenn es zu keinem StackOverflow kommt, ist eine solches Design natürlich unübersichtlicher als wenn man innerhalb eines Threads die Aktion rein sequentiell programmieren kann (natürlich parallel zu den anderen Thread).

Zum dritten müsste man bei jeder weiteren Klasse mit langlaufenden Operationen das Muster immer wieder neu implementieren. Sobald der Verwender auch nur auf eine Klasse stößt, die das Muster nicht implementiert, muss er sich eh selber um das Threading kümmern. Statt an den Stellen, an denen es geht, das Muster zu verwenden und an anderen Stellen sowieso nicht um eigene Threads herumzukommen, kann man sich gleich angewöhnen, immer eigene Threads zu verwenden und hat damit eine einheitliche Vorgehensweise für alle Fälle.

Aus all diesen Gründen, finde ich das Muster zu kompliziert, zu spezifisch, zu unflexibel und zu unpraktikabel. Ich rate vom Einsatz des Musters dringend ab.

herbivore

3.971 Beiträge seit 2006
vor 14 Jahren

Das asynchrone Entwurfsmuster verwendet keine Threads sondern IO Completition Ports um die Fertigstellung einer bestimmten Funktion zu Signalisieren (Callback-Funktion). Das ist der große Vorteile gegenüber einer Verwendung eines eigenes Threads oder Backgroundworker.

Beispiel, der Netzwerkcontroller führt die Callback-Funktion erst aus, wenn Daten auch wirklich am jweiligen Controller angekommen sind. Die CPU oder das Betriebssystem wird dafür nicht beansprucht. Bei einer Eigenimplementierung verschwende ich entweder einen Thread der ständig mit Polling prüft ob Daten angekommen sind oder ich verschwende einen Thread der ständig blockiert, weil er auf das Eintreffen wartet.

Allerdings macht das asynchrone Entwurfsmuster nur beim Zugriff auf IO sinn. Für die Berechnung und Weiterverarbeitung der Daten gibt es bessere "Entwurfsmuster" oder Frameworks wie beispielsweise die Parallel Fx Library (.NET v4).

Leider kommt das mit den IO Completition Ports bei Microsoft nicht so direkt rüber.

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...

49.485 Beiträge seit 2005
vor 14 Jahren

Hallo kleines_eichhoernchen,

Bei einer Eigenimplementierung verschwende ich entweder einen Thread der ständig mit Polling prüft ob Daten angekommen sind oder ich verschwende einen Thread der ständig blockiert, weil er auf das Eintreffen wartet.

nein, das würde man natürlich nicht tun. Man würde ja einfach (natürlich in einem extra Thread) die synchrone statt der asynchronen Methode verwenden. Jedenfalls ist das das, was ich die ganze Zeit sage. Und die synchrone Methode wird mindestens genauso effizient implementiert sein wie die asynchrone. Sollten IO Completition Ports die beste Lösung sein, wird auch die synchrone Methode sie intern verwenden. Ich kann daher den Einwand nicht gelten lassen.

Beispiel, der Netzwerkcontroller führt die Callback-Funktion erst aus, wenn Daten auch wirklich am jweiligen Controller angekommen sind.

Genauso wie die synchrone Methode erst zurückkehrt, wenn die Daten auch wirklich am jeweiligen Controller angekommen sind. Es gibt also kein Vorteil durch die asynchrone Methode.

herbivore

3.971 Beiträge seit 2006
vor 14 Jahren

Bei der synchronen Variante blockiert der jeweilige Thread. Bei der asynchronen Variante gibts kein Thread der blockiert, hab damit also einen Thread eingespart, der dann nützlichere Dinge machen kann als "nur zu warten". Gilt natürlich nur, wenn End nicht vor der Fertigstellung gerufen wurde.

Die asynchrone Variante bringt nicht wirklich viel, wenn ich nur übers Netzwerk ein Hello World ausgeben lassen möchte. Wo es hingegen um wichtige Ressourcen und Geschwindigkeit/Parallelisierung geht hat die Variante definitiv ihre Vorzüge zur synchronen Variante.

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...

49.485 Beiträge seit 2005
vor 14 Jahren

Hallo kleines_eichhoernchen,

Bei der synchronen Variante blockiert der jeweilige Thread.

bei der asynchronen Variante passiert genau das gleiche, nur dass der Thread implizit und nicht explizit verwendet wurde. In irgendeinem Thread muss die Aktion, die die Methode ausführt, ja laufen. Im Beispiel oben wird der Thread durch Delegate.BeginInvoke angestoßen, also ein ThreadPool-Thread verwendet.

Ich hoffe, dass du nicht auf den Unterschied von Thread-Klasse und ThreadPool-Threads hinaus willst. Dazu habe ich ja oben schon was geschrieben. Wenn ich "Thread" schreibe meine ich damit also nicht automatisch einen durch new Thread erzeugten Thread.

Bei der asynchronen Variante gibts kein Thread der blockiert, hab damit also einen Thread eingespart, der dann nützlichere Dinge machen kann als "nur zu warten".

Sorry, alles falsch.

herbivore

M
1.439 Beiträge seit 2005
vor 14 Jahren

Hallo Herbivore,

Sofern bei der asynchronen Variante I/O Completion Ports verwendet werden, hat kleines_eichhoernchen sehr wohl Recht.
Beid er synchronen Variante ist der (ThreadPool-)Thread blockiert bis die I/O-Operation abgeschlossen ist.
Bei der asynchronen Variante hingegen kehrt der Thread sofort wieder zurück und kann wieder andere I/O-Operationen abarbeiten. Sobald die I/O-Operation fertig ist, wird der Callback in einem ThreadPool Thread ausgeführt. Dadurch ist eine bessere Auslastung der Threads möglich.

F
10.010 Beiträge seit 2004
vor 14 Jahren

Das heisst, du machst den erhöten aufwand um dann doch nur wieder einen Threadpoolthread zu bekommen?

M
1.439 Beiträge seit 2005
vor 14 Jahren

Zum einen kann es sein, dass nicht die einzelne Methode langlaufend ist, sondern erst das Zusammenspiel vieler Methoden oder der Aufruf einer Methode in einer Schleife. Dann nützt einem das Muster nichts.

Doch natürlich, ich kann im Callback ja weitere Aktionen anstoßen.

Zum zweiten könnte es sein, dass man mehrere (asynchrone) Methoden hintereinander ausführen möchte. Dann bekommt man eine Art (End-)Rekursion (also aus dem Callback die nächste Methode aufrufen, die wieder einen Callback aufruf, ...) und bekommt damit möglicherweise einen StackOverflow.

Der callback wird normalerweise in einem anderen Thread ausgeführt, so dass es nicht zu einem StackOverflow kommt.

Zum dritten müsste man bei jeder weiteren Klasse mit langlaufenden Operationen das Muster immer wieder neu implementieren. Sobald der Verwender auch nur auf eine Klasse stößt, die das Muster nicht implementiert, muss er sich eh selber um das Threading kümmern.

Leider gibt es in der Informatik kein Muster mit dem man alles abdecken kann. Allerdings bieten alle wichtigen .Net Klassen dieses Muster an, so dass viele wichtige Operationen abgedeckt sind.

Aus all diesen Gründen, finde ich das Muster zu kompliziert, zu spezifisch, zu unflexibel und zu unpraktikabel. Ich rate vom Einsatz des Musters dringend ab.

Kompliziert vielleicht, allerdings ist das Thema Multithreading - egal wie man es löst - nicht einfach.
Unflexibel und Unpraktisch sicher nicht. Ganz im Gegenteil! Dieses Muster ist viel flexibler als alles in einem eigenen Thread laufen lassen.

Es gibt Anwendungen, in denen das asynchrone Muster einfacher zu implementieren ist und bessere Leistung ermöglicht. Ebenso gibt es wiederum Anwendungsfälle, bei denen ein eigener Thread die bessere Lösung ist.
Als guter Programmierer muss man halt abwegen, welches Muster ich einsetze. Hier einfach eine Möglichkeit auszuschließen, halte ich für falsch.

M
1.439 Beiträge seit 2005
vor 14 Jahren

Das heisst, du machst den erhöten aufwand um dann doch nur wieder einen Threadpoolthread zu bekommen?

Erhöhter Aufwand? Ich finde z.B. das von mir gepostete Beispiel einfacher, als einen eigenen Thread zu erzeugen oder Backgroundworker zu nehmen.

Naja, irgendwo muss ja der callback ja auch ausgeführt werden. Der Vorteil ist eben dass der Threadpool-Thread sofort wieder frei wird und andere Anfragen abarbeiten kann, während bei synchroner Ausführung der Thread blockiert.

Aber wie ich bereits Herbivore geschrieben habe, sollte man nicht dogmatisch immer ein Muster anwenden, sondern sich je nach Anwendungsfall für das beste Muster entscheiden.

S
8.746 Beiträge seit 2005
vor 14 Jahren

BTW: Die asynchronen Methoden geben einem einfach die Möglichkeit via WaitAny() auf verschiedene Ergeignisse zu warten, u.a. auf die Beendigung der Operation. Typischer Anwendungfall ist das Abbrechen einer asynchronen Operation durch ein externes Ereignis.

3.971 Beiträge seit 2006
vor 14 Jahren

Das heisst, du machst den erhöten aufwand um dann doch nur wieder einen Threadpoolthread zu bekommen?

Nein, ein Thread wird erst aus dem Pool genommen wenn, der jweilige asynchrone Task abgeschlossen wurde und auch nur wenn du ein Callback-Delegaten übergibst.

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...

3.971 Beiträge seit 2006
vor 14 Jahren

Hallo Herbivore,
Threading in C# (ziemlich weit unten)

Asynchronous Methods
Some types in the .NET Framework offer asynchronous versions of their methods, with names starting with "Begin" and "End". These are called asynchronous methods and have signatures similar to those of asynchronous delegates, but exist to solve a much harder problem: to allow more concurrent activities than you have threads. A web or TCP sockets server, for instance, can process several hundred concurrent requests on just a handful of pooled threads if written using NetworkStream.BeginRead and NetworkStream.BeginWrite.

Auch sehr interessant ist der Absatz zuvor

Asynchronous Delegates
Asynchronous delegates offer a convenient mechanism for this, allowing any number of typed arguments to be passed in both directions. Furthermore, unhandled exceptions on asynchronous delegates are conveniently re-thrown on the original thread, and so don't need explicit handling

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...

49.485 Beiträge seit 2005
vor 14 Jahren

Hallo marsgk,

Zum einen kann es sein, dass nicht die einzelne Methoden langlaufend ist, sondern erst das Zusammenspiel vieler Methoden oder der Aufruf einer Methode in einer Schleife. Dann nützt einem das Muster nichts.
Doch natürlich, ich kann im Callback ja weitere Aktionen anstoßen.

du hast nicht verstanden, worauf ich hinauswollte. Wenn die einzelnen Methode nur sehr kurz laufen, werden sie gar nicht in einer asynchronen Variante vorliegen. Deshalb kann man das Muster in diesem (typischen und verbreiteten) Fall nicht benutzen.

Als guter Programmierer muss man halt abwegen, welches Muster ich einsetze. Hier einfach eine Möglichkeit auszuschließen, halte ich für falsch.

Du verteidigst hier ein Muster, dass nur in absoluten Ausnahmefällen einen Vorteil hat. Und selbst in solchen Ausnahmefällen, muss man nicht zwingend dieses Muster einsetzen, um zum Erfolg zu kommen. Deshalb kann man es in meinen Augen getrost ausschließen.

Hallo kleines_eichhoernchen,

Nein, ein Thread wird erst Nein, ein Thread wird erst aus dem Pool genommen wenn, der jweilige asynchrone Task abgeschlossen wurde

und in welchen Thread läuft dann die asynchrone Task? Ich meine in dem Fall, der hier zur Diskussion steht, wo die asynchrone Task mit <delegate>.BeginInvoke aufgerufen wird. Doch wohl auch in einem ThreadPool-Thread.

Nur wenn wir über sowas wie I/O Completion Ports o.ä. kommt man doch drum rum, dass ein Thread laufen muss, um die asynchrone Task auszuführen. Das wird aber alles andere als der Normalfall sein.

herbivore