none
Frage zum Einsatz von Threads in einer WinForm-Applikation RRS feed

  • Frage

  • Hallo

    ich hätte eine Frage zum Einsatz von Threads in einer WinForm (MDI-Applikation).

    Während der Benutzer in dieser MDI-Applikation in verschiedenen Forms arbeitet (Verwendung des EntityFramework für die Daten-Selektion und Verwaltung), muss ich in der MainForm einen Timer erstellen, der in gewissen Abständen für den angemeldeten Benutzer ToDO-Datensätze aus der Datenbank liest, und noch ein zweiter Lesevorgang für Nachrichten zu dieser Applikation. Jetzt dachte ich daran, dieses Funktionen die regelmäßig vom Timer angestartet werden (Timer-Zeit wird zwischen 30 Sek. und 1 Minute liegen) mit eigenen Threads zu lösen.

    Ich habe gelesen, dass Threads das ganze auch langsamer machen können/könnten. Und wenn ich an die Rechner bei dem Kunden denke, gibt es fast nur 1 Prozessor-Maschinen.

    Ist der Einsatz von Thread-Programmierung für solch eine Anwendung sinnvoll ??

    Vielleicht kann mir dazu hier jemand ein paar Tipps dazu geben.

    Danke schon mal & schönen Gruß

    Michael

     

     


    Michael Erlinger
    Mittwoch, 25. Mai 2011 06:06

Antworten

  • Hallo Michael,

    im Szenario von Prozessoren mit einem Kern würde Threading keinen effektiven positiven Effekt bzgl. Performance haben. Der Overhead der neuen Threads (bzw. Verwaltung) kann sogar negativ sein - wenn auch normal marginal.

    Wenn die Timer-Zeit zwischen 30 Sek und einer Minute liegt, sollte man normal einen System.Windows.Forms.Timer benutzen. Hier ist auch der Vorteil, dass ein mögliches Marshalling in den MainThread (etwa für Aktionen, die Controls auf der Form betreffen) nicht notwendig ist, weil der Handler im MainThread bedient wird.

    [Threading in C# - Free E-book]
    http://www.albahari.com/threading/#_Threads_vs_Processes


    ciao Frank
    Mittwoch, 25. Mai 2011 06:58
  • Hallo Michael,

    Ist der Einsatz von Thread-Programmierung für solch eine Anwendung sinnvoll ??

    Jein. Aus der Dokumentation:

    "Auf einem Computer mit einem einzelnen Prozessor können eine Aufgabe, die eine ressourcenintensive Berechnung erfordert, und Benutzereingaben oder Aufgaben mit E/A-Vorgängen problemlos gleichzeitig ausgeführt werden. Mehrere rechenintensive Aufgaben machen sich jedoch gegenseitig die Ressourcen streitig."

    Wenn das Holen der ToDo-Daten also nicht allzu rechenintensiv ist, kein Problem. Verwende einfach einen BackgroundWorker und einen Timer. Du könntest den Timer nach erfolgter Datenaktualisierung deaktivieren und das Application.Idle-Ereignis abonnieren. Sobald die Anwendung in den Leerlauf wechselt, könntest Du den Timer wieder aktivieren (evtl. checkst Du vorher noch System.Diagnostics.Process.GetCurrentProcess().TotalProcessorTime ab). Zusätzliche Infos zum Idle-Status kannst Du dir über die GetLastInputInfo Windows API-Funktion besorgen.

    Empfohlene Vorgehensweise für das verwaltete Threading (s. Anzahl der Prozessoren):
    http://msdn.microsoft.com/de-de/library/1c9txz50.aspx

    s.a. Detecting Application Idleness:
    http://www.codeproject.com/KB/cs/ApplicationIdle.aspx

    Gruß
    Marcel


    Mittwoch, 25. Mai 2011 11:42
    Moderator

Alle Antworten

  • Hallo Michael,

    im Szenario von Prozessoren mit einem Kern würde Threading keinen effektiven positiven Effekt bzgl. Performance haben. Der Overhead der neuen Threads (bzw. Verwaltung) kann sogar negativ sein - wenn auch normal marginal.

    Wenn die Timer-Zeit zwischen 30 Sek und einer Minute liegt, sollte man normal einen System.Windows.Forms.Timer benutzen. Hier ist auch der Vorteil, dass ein mögliches Marshalling in den MainThread (etwa für Aktionen, die Controls auf der Form betreffen) nicht notwendig ist, weil der Handler im MainThread bedient wird.

    [Threading in C# - Free E-book]
    http://www.albahari.com/threading/#_Threads_vs_Processes


    ciao Frank
    Mittwoch, 25. Mai 2011 06:58
  • Hallo Michael,

    Ist der Einsatz von Thread-Programmierung für solch eine Anwendung sinnvoll ??

    Jein. Aus der Dokumentation:

    "Auf einem Computer mit einem einzelnen Prozessor können eine Aufgabe, die eine ressourcenintensive Berechnung erfordert, und Benutzereingaben oder Aufgaben mit E/A-Vorgängen problemlos gleichzeitig ausgeführt werden. Mehrere rechenintensive Aufgaben machen sich jedoch gegenseitig die Ressourcen streitig."

    Wenn das Holen der ToDo-Daten also nicht allzu rechenintensiv ist, kein Problem. Verwende einfach einen BackgroundWorker und einen Timer. Du könntest den Timer nach erfolgter Datenaktualisierung deaktivieren und das Application.Idle-Ereignis abonnieren. Sobald die Anwendung in den Leerlauf wechselt, könntest Du den Timer wieder aktivieren (evtl. checkst Du vorher noch System.Diagnostics.Process.GetCurrentProcess().TotalProcessorTime ab). Zusätzliche Infos zum Idle-Status kannst Du dir über die GetLastInputInfo Windows API-Funktion besorgen.

    Empfohlene Vorgehensweise für das verwaltete Threading (s. Anzahl der Prozessoren):
    http://msdn.microsoft.com/de-de/library/1c9txz50.aspx

    s.a. Detecting Application Idleness:
    http://www.codeproject.com/KB/cs/ApplicationIdle.aspx

    Gruß
    Marcel


    Mittwoch, 25. Mai 2011 11:42
    Moderator
  • Hallo Marcel,

    • Michael schrieb: "... Thread-Programmierung für solch eine Anwendung [gemeint ist Ein-Kern-Prozessor] sinnvoll ??"
    • Du schriebst: Jein. Aus der Dokumentation ...

    nur, damit das richtig verstanden wird ... der Doku-Absatz bezieht sich auf die Möglichkeit des gleichzeitigen Ressourcen-Zugriffes, der ist m.E. möglich. Da aber in einem Ein-Kern-Prozessor-Szenario zu jedem Zeitpunkt immer nur ein Thread ausgeführt werden kann, bringt es aus Sicht der Performance nichts. Also aus dem Performance-Gesichtspunkt, eher keinen Backgroundworker wählen (da hat Michael schon richtig gelesen). Natürlich könnten andere Implementations-Vorlieben/Anforderungen ein Rolle spielen, also die Möglichkeit ist da.


    ciao Frank
    Mittwoch, 25. Mai 2011 13:30
  • Frank schrieb:

    Da aber in einem Ein-Kern-Prozessor-Szenario zu jedem Zeitpunkt immer nur ein Thread ausgeführt werden kann, bringt es aus Sicht der Performance nichts.

    Das Verwenden eines zweiten Hintergrundthreads - so wie ich das vorgeschlagen habe - hat nichts mit der Perfomance zu tun, sondern mit der Reaktionsfähigkeit der Anwendung. Das Laden der ToDo-Daten auf einer Ein-Kern-Maschine im UI-Thread würde die UI für die Dauer des Updates lahmlegen. Daher die Notwendigkeit des zweiten Threads mit all den beschriebenen Details. Öffne doch einfach den TaskManager auf einer Ein-Kern-Maschine und beschreib mir, was Du in der Spalte Threads siehst. Wenn da überall 1 steht, dann hast Du recht. Aber wir wollen den Windows Scheduler nicht arbeitslos machen, oder?

    "Multitasking is the operating system technique for sharing a single processor among multiple
    threads of execution. When a computer has more than one processor, however, it can execute
    multiple threads simultaneously. Thus, whereas a multitasking operating system only appears to
    execute multiple threads at the same time, a multiprocessing operating system actually does it,
    executing one thread on each of its processors."

    (M. Russinovich, D. Solomon, Alex Ionescu - Windows Internals. 5th ed. Microsoft Press, 2009. S. 39)



    Mittwoch, 25. Mai 2011 14:26
    Moderator
  • Hallo Marcel,

    wie gesagt, ich erwähne das, damit man nicht denkt, man würde damit Performance gewinnen - eher verlieren - das sollte nur geklärt werden.

    Bzgl. Reaktionsfähigkeit bin ich Deiner Meinung. Die Anzahl der Threads im Taskmanager spielen allerdings dabei weniger eine Rolle. 
    Wichtig ist eher, dass es dann durch MultiTasking eine Schein-Gleichzeitgkeit gibt [ah, ich sehe gearade, Du hast den Punkt Multitasking jetzt in Deinem Posting auch nachgetragen/bearbeitet, denn Du hattest ihn vorher gar nicht erwähnt] (intern weiterhin nur auf einem Kern hintereinander mit Thread-Verwaltungs-Overhead). Für Tests auf Mehrkernmaschinen würde man übrigens nicht unbedingt eine "Ein-Kern-Maschine" benötigen - es reicht etwas wie: 

    Process.GetCurrentProcess().ProcessorAffinity = new IntPtr(1);
    

     


    ciao Frank


    Mittwoch, 25. Mai 2011 15:26