none
Anwendung wird langsamer und "verstopft" RRS feed

  • Frage

  • Schönen guten Abend,

    ich habe hier eine Windows-Forms-Anwendung und die dazu gedacht ist, IP-Adressen der Reihe nach unzupingen um so den Status des jeweiligen Rechners festzustellen. Leider taugt das Programm in der Langzeit nichts, da immer wenn man das Programm 10 - 20 Minuten alleine laufen lässt, folgendes Problem auftritt:

     

    Nach dem Start läuft das Programm ganz normal, wenig CPU Auslastung und keinerlei Einschränkungen in der Funktion.

    Nach den oben angegebenen 10 bis 20 Minuten, fällt es dem Programm schwerer die Einträge in die ListBox zu schreiben, was heißt die CPU-Auslastung geht hoch und die Einträge fangen an zu flimmern, allgemein verhält sich die gesamte Anwendung nur noch träge. Mit zunehmender Zeit wird es auch immer schlimmer, bis schließlich fast gar nichts mehr läuft. Ich wollte davon ein Screenshot machen, aber leider habe ich es nicht drauf bekommen, sodass man es richtig sieht.

     

    Jetzt noch was zum Code:

    Der Klick auf den Startbutton startet einen Timer, der Timer wiederum startet immer wieder einen Backgroundworker, der wiederum im Hintergrund das anpingen übernimmt. Habe ihn hier mal angehängt:

        private void PingWorker_DoWork(object sender, DoWorkEventArgs e)
        {
    
          BackgroundWorker worker = sender as BackgroundWorker;
          // Liste der Hosts als Argument
     string[] hostNames = e.Argument as string[];
    
          if (hostNames != null && hostNames.Length != 0)
          {
            foreach (string hostname in hostNames)
            {
              // Abbrechen...
              if (worker.CancellationPending)
              {
                e.Cancel = true;
                break;
              }
    
              if (!String.IsNullOrEmpty(hostname))
              {
    
    
    
                  Functions functions = new Functions();
              if ( functions.IsIP(hostname) == true)
              {
    
    
    
                  IP_Hostname iphost = new IP_Hostname();
                  hostnamefromip = iphost.IP_zu_Hostname(hostname);
                }
                else
                {
                  hostnamefromip = hostname;
                }
    
                // Host abfragen...
                string message = null;
                try
                {
                  using (Ping pingSender = new Ping())
                  {
    
    
                    reply = pingSender.Send(hostname, PingTimeout);
                    if (reply.Status == IPStatus.Success && showonlyoffline.Checked != true)
                    {
                      DateTime currentDate = DateTime.Now;
    
                      successfull = 1;
                      message = String.Format("[{0}:{1}:{2}]{3}({4}): {5} ms",
                        currentDate.Hour, currentDate.Minute, currentDate.Second, hostname, hostnamefromip, reply.RoundtripTime);
    
                    }
                    else
                      if (reply.Status == IPStatus.Success)
                      {
                        message = "";
                      }
                      else
                      {
                        DateTime currentDate = DateTime.Now;
                        successfull = 2;
                        message = String.Format("[{0}:{1}:{2}]{3}({4}): {5} ms",
                          currentDate.Hour, currentDate.Minute, currentDate.Second, hostname, hostnamefromip, reply.RoundtripTime);
                      }
                  }
                }
    
                catch (Exception)
                {
                  DateTime currentDate = DateTime.Now;
                  message = String.Format("{0}: Ungültiges Zeichen!",
                  hostname);
    
                  successfull = 3;
                  message = String.Format("[{0}:{1}:{2}]{3}({4}): TimedOut",
                     currentDate.Hour, currentDate.Minute, currentDate.Second, hostname, hostnamefromip);
    
                }
    
    
    
    
                // Aktualisieren hier als Text
                this.pingListBox.DrawItem += new DrawItemEventHandler(pingListBox_DrawItem);
                worker.ReportProgress(hostNames.Length / 100 + 1, message);
    
    
              }
    
            }
    
          }
          if (cb_repeatping.Checked == true)
          {
            System.Threading.Thread.Sleep(repeatvalue);
            
          }
          else
          {
            
            t.Stop();
          }
          
        }
    
     
    
    
        private void PingWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
    
          //this.cancelButton.Enabled = false;
          this.startButton.Enabled = true;
          this.label1.Text = "Status: Durchlauf beendet";
          
    
    
    
    
    
    
    
        }
    
        private void PingWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
          string message = e.UserState as string;
    
          // Anzeige der Nachricht in einer ListBox
          if (!String.IsNullOrEmpty(message))
          {
            
    
            this.pingListBox.Items.Add(new MyListBoxItem(message, successfull));
    
            pingListBox.TopIndex = pingListBox.Items.Count - 1;
          }
          if (pingListBox.Items.Count >= maxlistboxentrys)
          {
            
            pingListBox.Items.RemoveAt(0);
          }
        }
    
    
    
    
        private void t_Tick(object sender, EventArgs e)
        {
             // Startet die Abfrage über einen BackgroundWorker
          if (!this.pingWorker.IsBusy)
          {
            // Einlesen der Hostnamen in ein Array
            string[] hostNames = System.IO.File.ReadAllLines(HostNames);
    
            // Asynchron abrufen
            this.pingWorker.RunWorkerAsync(hostNames);
            label1.Text = "Status: Durchlauf gestartet";
    
    
    
          }
        }
    
        public void startButton_Click(object sender, EventArgs e)
        {
          if (tb_maxlistboxentrys.Text == "" || tb_maxlistboxentrys.Text == "0")
          {
          tb_maxlistboxentrys.Text = "16";
          }
          else
          {
            t.Start();
            this.cancelButton.Enabled = true;
            this.label1.Text = "Status: Durchlauf gestartet";
          }
          
        }
    

     

    So, ich hoffe ihr könnt mir helfen, habe schon verschiedenes probiert, z.B. Die ListBox Einträge auf ein Maximum zu setzen, weil ich dachte das die irgendwann zu voll wird und "verstopft" aber daran lag es nicht. Nun habe ich mir vielleicht überlegt, ob es helfen würde nach jedem Ping 200ms zu warten oder so.

    Oder muss ich den Backgroundworker etc. irgendwie wieder "closen" bevor er erneut aufgerufen wird?

     

    Falls ich etwas vergessen habe, tut mir leid, dann werde ich es nachtragen!

     

    RunTime

    Freitag, 5. November 2010 22:49

Antworten

  • Hallo R.,

    Der BackgoundWorker benutzt Threads aus dem ThreadPool (Hintergrundthreads). Dieser Pool hat eine Begrenzung von Anforderungen, die gleichzeitig aktiv sein können. Diese Anzahl kann über die Methode ThreadPool.GetMaxThreads ermittelt werden.
    Zwar kann für geringe Anzahlen von Threadpool-Thread-Anforderungen der BackgroundWorker oft gut eingesetzt werden, aber einer der Gründe, die gegen die Verwendung von Threadpoolthreads sprechen, ist:

    • Da die Anzahl der Threads im Threadpool begrenzt ist, kann eine hohe Anzahl blockierter Threadpoolthreads das Starten von Aufgaben verhindern. Quelle u.a.: [Verwalteter Threadpool]
    • Angefangen im .NET 4.0 Framework hängt die Standard-Größe des ThreadPools für einen Prozess von vielfältigen Faktoren ab, wie etwa die Größe des virtuellen Addressraumes. Trotzdem kann man sich eine grobe Vorstellung von den Maxima machen, die in etwa lautet: Die maximal gleichzeitigen aktiven Pool-Threads sind ~ca.: 1023 in .NET 4.0 32Bit, 32768 in .NET 4.0 64Bit, in .NET 3.5 waren es aber sogar nur 250 je Core, in .NET 2.0 nur 25 pro Core! [Quelle u.a. hier].
      Ist diese Maximum erreicht, werden diese ge-queued und insgesamt ergeben sich immer ineffizentere Verhaltensweisen. Dies ist also zu vermeiden.

    Das manuelle Setzen dieser maximal gleichzeitig aktiven Pool-Threads kann zwar gesetzt werden ist aber i.d.R. nicht empfohlen.

    In Deinem Fall kann es sein, dass sehr (bzw. zu) viele Hintergrund-Threads gleichzeitig angefordert werden, weil sie u.a. auch teilweise länger für ihre Bendigung brauchen. Insofern würde ich ggf. alternative, oder mehr kontrollierendes Thread-Handling in Deinem Fall in Betracht ziehen. Solche Strategien kannst Du zum Beispiel hier gut überblicken: [Threading in C# - Free E-book]

     


    ciao Frank
    • Als Antwort vorgeschlagen Frank Dzaebel Sonntag, 7. November 2010 18:44
    • Als Antwort markiert Run-Time Sonntag, 7. November 2010 20:43
    Samstag, 6. November 2010 10:33
  • R,

    also ist damit reproduzierbar, aber:

    Abgesehen dass der Start-Button-Click zweimal verknüpft ist (designer und ctor manuell nochmals) und zahlreichen anderen unschönen Details:

    wie ich schon im allerersten Post ausdrücklich gewarnt habe, deine Zeile im Worker:
     this.pingListBox.DrawItem += new DrawItemEventHandler(pingListBox_DrawItem);
    ist purer Unsinn  (und Verursacht bei jedem Durchgang eine _vervielfachung_ der Zeichenvorgänge pro ListBox-Eintrag  (= CPU Last)!

    Ich vermute nun, du hast diese Zeile wieder eingefügt weil sonst nichts angezeigt wird?
    Dies hat aber die wohl Ursache, weil deine pingListBox.DrawMode  auf OwnerDraw  steht!!
    Mit 'Normal' dort habe ich akzeptable Performance (soweit man dies in Kürze feststellen kann, weitere defekte keinesfalls nicht ausgeschlossen)
    • Als Antwort vorgeschlagen Marcel RomaModerator Sonntag, 7. November 2010 20:03
    • Als Antwort markiert Run-Time Sonntag, 7. November 2010 20:24
    Samstag, 6. November 2010 18:27
  • Für deine 'eingefärbten' ListBox-Einträge  (mal nur funktionell):

    du solltest die 'böse' Zeile:
     this.pingListBox.DrawItem += new DrawItemEventHandler(pingListBox_DrawItem);

    eher ordentlich per Designer verknüpfen lassen  (ggf halt manuell im ctor).

    Nur, dann wird deine App evtl einen sehr 'schlechten' Start haben,
    weil deine pingListBox_DrawItem Methode (mind.) folgendes nicht berücksichtigt:

    http://msdn.microsoft.com/de-de/library/system.windows.forms.drawitemeventargs.index.aspx

      "Diese Eigenschaft kann -1 zurückgeben, wenn Elemente aus der Liste entfernt wurden"

    PS
    manchmal scheint es von Vorteil, solche Control-Eventhandler mit Exception-Handling zu versehen!
    • Als Antwort vorgeschlagen Marcel RomaModerator Sonntag, 7. November 2010 20:03
    • Als Antwort markiert Run-Time Sonntag, 7. November 2010 20:24
    Samstag, 6. November 2010 18:53
  • Hallo RT.,

    Du hast folgende Zeile im PingWorker_DoWork:

     this.pingListBox.DrawItem += new DrawItemEventHandler(pingListBox_DrawItem);

    Das bedeutet, Du abbonierst einen Handler immer wieder - jedesmal wenn DoWork aufgerufen wird.
    Er muss dann jedesmal alle abonnierten Handler abarbeiten, was nach mehreren Minuten äusserst ungünstig bzgl. der Performance sein kann :-)
    Also bei 100 Aufrufen von von DoWork muss dann 100 mal die Methode: "pingListBox_DrawItem" durchgeführt werden.
    Insofern ersetze das mal temporär durch etwas wie:

    this.pingListBox.DrawItem -= new DrawItemEventHandler(pingListBox_DrawItem);
    this.pingListBox.DrawItem += new DrawItemEventHandler(pingListBox_DrawItem);


    Das könnte also auch schon Dein Problem gewesen sein.
    Prüfe das erstmal, wenns dann noch nicht geht, melde Dich nochmal - dann arbeiten wir uns step by step an die Lösung.
     


    ciao Frank
    • Als Antwort vorgeschlagen Frank Dzaebel Sonntag, 7. November 2010 18:44
    • Als Antwort markiert Run-Time Sonntag, 7. November 2010 20:24
    Samstag, 6. November 2010 19:23

Alle Antworten

  •             // Aktualisieren hier als Text
                this.pingListBox.DrawItem += new DrawItemEventHandler(pingListBox_DrawItem);
    Hallo R

    habe den lückenhaften Code nicht geprüft, aber mind obige Zeile  (DrawItem +=)
    schaut äusserst sinnfrei aus.
    Und mit     t.Stop();    im Worker hätte ich auch bedenken, scheint doch ein Forms-Timer?
      (Stop gehört bei dir vermutlich auch in   PingWorker_RunWorkerCompleted)

    Ebenso der direkte (Lese-)Zugriff auf (CheckBox?)  cb_repeatping.Checked  im Worker, dies klappt wohl in aktuellen Framework Implementationen, aber garantiert für später (und meiste andere Properties!) ist da nichts.  (= schlechter Stil)
    Freitag, 5. November 2010 23:01
  • Okay, danke erstmal für deine Rasche antwort, die Tipps habe ich gerade verarbeitet, sie waren mir so nicht bewusst.

     

    - Die Zeile mit DrawItem habe ich rausgenommen, sie war wohl das überbleibsel von ein paar Experimenten mit dem Codeteil.

    - t.stop(); ist ein Forms-Timer, stimmt. Das habe ich aber nun auch durch pingWorker.CancelAsync(); ersetzt, eine etwas freundlichere Methode.

    - Zu dem direkten (Lese-)Zugriff auf die Checkbox, ich dachte mir, wenn ich für dafür jetzt noch eine extra Variable mache, belasstet das nur unnötig und ich kann besser direkt den Status der Checkbox abfragen. Das man das nicht macht, war mir bis jetzt nicht bewusst, werde es aber nun auch ändern!

     

     

     

     

     

    Freitag, 5. November 2010 23:40
  • - t.stop(); ...  durch pingWorker.CancelAsync(); ersetzt
    nur zur Sicherheit  (da nicht klar an welcher Stelle ersetzt wurde)
    ein Aufruf von CancelAsync  im Worker selber   (PingWorker_DoWork Methode) macht keinerlei Sinn.

    PS, des weiteren auch
    showonlyoffline.Checked ist nicht sauber.
    Freitag, 5. November 2010 23:49
  • Tut mir leid, habe ich vergessen, geändert hatte ich es im PingWorker_DoWork(....) und nun diesen Abschnitt ganz rausgenommen: 

    if (var_repeatpingChecked == true) 
    { 
    
    System.Threading.Thread.Sleep(repeatvalue);
    
    } 
    else 
    {
    
     t.Stop();
    
    } 

    Nun habe ich ihn in PingWorker_RunWorkerCompleted(...) verschoben und ein bisschen abgeändert:

    if (var_repeatpingChecked == true) 
    { 
    
    t.Interval = repeatvalue;
    
    
    }
     else 
    { 
    
    t.Stop(); 
    
    } 

    Er greift nun nicht mehr direkt auf die CheckBox zu und die Wartepause habe ich mit dem Timer gelöst. Ich hoffe das ist nun eleganter so.

    Aber mein Problem mit dem erlahmen und aufhängen des Programms löst das immernoch nicht

    Samstag, 6. November 2010 02:19
  • Aber mein Problem mit dem erlahmen und aufhängen des Programms löst das immernoch nicht

    R,
    deine Vorgehensweise ist zwar schwer nachzuvollziehen, aber mal noch zur Sicherheit, bei Zeile:
    if (pingListBox.Items.Count >= maxlistboxentrys)

    was für Wert hat  'maxlistboxentrys'?  (bzw überfüllt sich die ListBox sonstwie?)

    Und weiters, eine zu häufige Auslösung von 'ReportProgress'  (= Flut von ProgressChanged Events) kann auch ähnliche Effekte zeigen.
    Auch diese Reihenfolge in PingWorker_ProgressChanged:
     this.pingListBox.Items.Add, TopIndex, RemoveAt
    scheint mir (unter Last) wenig sinnvoll  (eher: Add, RemoveAt, TopIndex; evtl. Begin/EndUpdate drum)

    Da mit dem hier gezeigten Code zuviele Fragen offenbleiben,
    musst du selber systematischer Vorgehen (nach Backup - zB: schrittweise Code reduzieren),
    oder halt evtl ein _minimales_, aber für uns _kompilierbares_ Beispielprojekt vorbereiten (langen Source eher nicht hier post, sondern in ZIP bei einem Download-Dienst)
    Wobei deine Netzwerkumgebung  (Datei HostNames) nicht unbedingt anderswo (identisch) läuft.
    Samstag, 6. November 2010 08:34
  • Hallo R.,

    Der BackgoundWorker benutzt Threads aus dem ThreadPool (Hintergrundthreads). Dieser Pool hat eine Begrenzung von Anforderungen, die gleichzeitig aktiv sein können. Diese Anzahl kann über die Methode ThreadPool.GetMaxThreads ermittelt werden.
    Zwar kann für geringe Anzahlen von Threadpool-Thread-Anforderungen der BackgroundWorker oft gut eingesetzt werden, aber einer der Gründe, die gegen die Verwendung von Threadpoolthreads sprechen, ist:

    • Da die Anzahl der Threads im Threadpool begrenzt ist, kann eine hohe Anzahl blockierter Threadpoolthreads das Starten von Aufgaben verhindern. Quelle u.a.: [Verwalteter Threadpool]
    • Angefangen im .NET 4.0 Framework hängt die Standard-Größe des ThreadPools für einen Prozess von vielfältigen Faktoren ab, wie etwa die Größe des virtuellen Addressraumes. Trotzdem kann man sich eine grobe Vorstellung von den Maxima machen, die in etwa lautet: Die maximal gleichzeitigen aktiven Pool-Threads sind ~ca.: 1023 in .NET 4.0 32Bit, 32768 in .NET 4.0 64Bit, in .NET 3.5 waren es aber sogar nur 250 je Core, in .NET 2.0 nur 25 pro Core! [Quelle u.a. hier].
      Ist diese Maximum erreicht, werden diese ge-queued und insgesamt ergeben sich immer ineffizentere Verhaltensweisen. Dies ist also zu vermeiden.

    Das manuelle Setzen dieser maximal gleichzeitig aktiven Pool-Threads kann zwar gesetzt werden ist aber i.d.R. nicht empfohlen.

    In Deinem Fall kann es sein, dass sehr (bzw. zu) viele Hintergrund-Threads gleichzeitig angefordert werden, weil sie u.a. auch teilweise länger für ihre Bendigung brauchen. Insofern würde ich ggf. alternative, oder mehr kontrollierendes Thread-Handling in Deinem Fall in Betracht ziehen. Solche Strategien kannst Du zum Beispiel hier gut überblicken: [Threading in C# - Free E-book]

     


    ciao Frank
    • Als Antwort vorgeschlagen Frank Dzaebel Sonntag, 7. November 2010 18:44
    • Als Antwort markiert Run-Time Sonntag, 7. November 2010 20:43
    Samstag, 6. November 2010 10:33
  • Okay, danke für deine Erklärung, sowas in der Art habe ich mir auch schon gedacht. Ich arbeite mich mal durch die verschiedenen Links und sach dann bescheid, wenn ich zu einem Ergebnis gekommen bin!


    Danke nochmal an euch!

    Samstag, 6. November 2010 10:54
  • sowas in der Art habe ich mir auch schon gedacht.
    R,
    viel mehr stellten sich dann die Fragen (von vielen immer noch offenen) zu deinem geposteten Code:
    1) was für ein kurzes Timer-Intervall du gewählt hast
    2) wieviele Worker du parallel laufen lässt, obschon eigentlich nur eine Instanz (this.pingWorker) gehalten wird, und Prüfung auf  this.pingWorker.IsBusy eigentlich im Code  (t_Tick-Event) wäre!?

    Ohne Klarheit im Code schätze ich (vorerst) die Ursache als vermutlich kaum in .NET-Internas/Limiten.
    Samstag, 6. November 2010 13:13
  • Hallo R.,

         > Okay, danke für deine Erklärung, sowas in der Art habe ich mir auch schon gedacht.

    gerne.

    Wenn Du willst, kannst Du mir Deinen bisherigen Code auch zukommen lassen. -> Post[Add]FranksSeite.de
    Dann könnte ich mir ein Bild machen - aber ich denke, mit meinen Hinweisen/Links (u.a. den Beschränkungen bzgl. des ThreadPools) sollte sich das von Dir in den Griff bekommen lassen.

     

         > ... und sach dann bescheid, wenn ich zu einem Ergebnis gekommen bin!

    perfekt, ist sicher sehr lehrreich auch für andere später.

     


    ciao Frank
    Samstag, 6. November 2010 13:24
  • Okay, ich habe mich in die Threadgeschichte nun schonmal etwas reingelesen, dann mir aber gedacht, weil der Code anscheinend sowieso unsauber programmiert ist, wollte ich ihn erstmal richtig ordnen. Da ich aber die markanten "brüchigen" Stellen nicht finde, dachte ich, ihr könnten mir dabei helfen.

    Ich habe den Code schon länger in Entwicklung mithilfe von Anleitungen und Beispielen zusammengestrickt. So habe ich es gelernt. Das da beim erstenmal nichts sinnvolles bei rauskommt ist dann auch klar. Ich habe bis heute halt einfach nach Funktion programmiert, ohne an irgenwelche Richtlinien zu denken.

     

    Wichtig ist, dass das hier kein Aufruf nach dem Motto: "Hilfe macht mir das mal, ich weiß nicht mehr weiter" ist, sondern das ich etwas daraus lernen möchte, wie man es vernümpftig macht. Es kann sein, das in dem Code nutzlose Fetzen rumschweben, da ich auch mit bestimmeten Funktionen experementiert habe.

     

    Projekt rausgenommen, bei Bedarf oder wer es gerne sehen möchte, kann sich mit einer Nachricht an mich wenden!
    • Bearbeitet Run-Time Sonntag, 7. November 2010 20:46
    Samstag, 6. November 2010 17:04
  • R,

    also ist damit reproduzierbar, aber:

    Abgesehen dass der Start-Button-Click zweimal verknüpft ist (designer und ctor manuell nochmals) und zahlreichen anderen unschönen Details:

    wie ich schon im allerersten Post ausdrücklich gewarnt habe, deine Zeile im Worker:
     this.pingListBox.DrawItem += new DrawItemEventHandler(pingListBox_DrawItem);
    ist purer Unsinn  (und Verursacht bei jedem Durchgang eine _vervielfachung_ der Zeichenvorgänge pro ListBox-Eintrag  (= CPU Last)!

    Ich vermute nun, du hast diese Zeile wieder eingefügt weil sonst nichts angezeigt wird?
    Dies hat aber die wohl Ursache, weil deine pingListBox.DrawMode  auf OwnerDraw  steht!!
    Mit 'Normal' dort habe ich akzeptable Performance (soweit man dies in Kürze feststellen kann, weitere defekte keinesfalls nicht ausgeschlossen)
    • Als Antwort vorgeschlagen Marcel RomaModerator Sonntag, 7. November 2010 20:03
    • Als Antwort markiert Run-Time Sonntag, 7. November 2010 20:24
    Samstag, 6. November 2010 18:27
  • Für deine 'eingefärbten' ListBox-Einträge  (mal nur funktionell):

    du solltest die 'böse' Zeile:
     this.pingListBox.DrawItem += new DrawItemEventHandler(pingListBox_DrawItem);

    eher ordentlich per Designer verknüpfen lassen  (ggf halt manuell im ctor).

    Nur, dann wird deine App evtl einen sehr 'schlechten' Start haben,
    weil deine pingListBox_DrawItem Methode (mind.) folgendes nicht berücksichtigt:

    http://msdn.microsoft.com/de-de/library/system.windows.forms.drawitemeventargs.index.aspx

      "Diese Eigenschaft kann -1 zurückgeben, wenn Elemente aus der Liste entfernt wurden"

    PS
    manchmal scheint es von Vorteil, solche Control-Eventhandler mit Exception-Handling zu versehen!
    • Als Antwort vorgeschlagen Marcel RomaModerator Sonntag, 7. November 2010 20:03
    • Als Antwort markiert Run-Time Sonntag, 7. November 2010 20:24
    Samstag, 6. November 2010 18:53
  • Hallo RT.,

    Du hast folgende Zeile im PingWorker_DoWork:

     this.pingListBox.DrawItem += new DrawItemEventHandler(pingListBox_DrawItem);

    Das bedeutet, Du abbonierst einen Handler immer wieder - jedesmal wenn DoWork aufgerufen wird.
    Er muss dann jedesmal alle abonnierten Handler abarbeiten, was nach mehreren Minuten äusserst ungünstig bzgl. der Performance sein kann :-)
    Also bei 100 Aufrufen von von DoWork muss dann 100 mal die Methode: "pingListBox_DrawItem" durchgeführt werden.
    Insofern ersetze das mal temporär durch etwas wie:

    this.pingListBox.DrawItem -= new DrawItemEventHandler(pingListBox_DrawItem);
    this.pingListBox.DrawItem += new DrawItemEventHandler(pingListBox_DrawItem);


    Das könnte also auch schon Dein Problem gewesen sein.
    Prüfe das erstmal, wenns dann noch nicht geht, melde Dich nochmal - dann arbeiten wir uns step by step an die Lösung.
     


    ciao Frank
    • Als Antwort vorgeschlagen Frank Dzaebel Sonntag, 7. November 2010 18:44
    • Als Antwort markiert Run-Time Sonntag, 7. November 2010 20:24
    Samstag, 6. November 2010 19:23
  • Okay, danke euch beiden, die böse Zeile habe ich mit der temporären Lösung ausgetauscht und sie funktioniert! Es lahmt nun nicht mehr nach 20 Minuten. Den Schritt dort kann ich nun nachvollziehen.

     

    Wie kann ich denn meinen Code weiter optimieren, also die unschönen stellen rausarbeiten?

    Sonntag, 7. November 2010 11:48
  • die böse Zeile habe ich mit der temporären Lösung ausgetauscht und sie funktioniert! Es lahmt nun nicht mehr nach 20 Minuten. Den Schritt dort kann ich nun nachvollziehen.
    R,
    dies ist so keine 'Lösung', sondern nur eine 'Vertuschung', taugt so höchstens als Schnelltest zum Debuggen.
    Wie ich schon hinlänglich oft gesagt habe, gehören solche Zeilen Code (Events von Controls  abonnieren) _nicht_ in den Worker,
    sondern sauber ausgearbeitet, zB im Designer verknüpft (lies meine Hinweise!).
    Und den möglichen Folgefehler (Index: -1)  habe ich ja auch erwähnt.
    Ich rate dir, _meine_ Postings endlich ernsthaft durchzuarbeiten!

    PS
    Beachte auch, dass man hier im Forum den richtigen Lösungsbeitrag markieren kann.
    Sonntag, 7. November 2010 12:17
  • Hallo RT.,

    Frank schrieb: "Insofern ersetze das mal temporär durch etwas wie: [...]"

         > ... habe ich mit der temporären Lösung ausgetauscht und sie funktioniert!

    das freut mich :-)


        > weiter optimieren ...

    Du brauchst jetzt "nicht" meine 2 Zeilen durch Designer-erzeugten Code ersetzen.
    Es ist aber ggf. sinnvoll, diese 2 von mir geposteten Zeilen einfach nur einmalig (als eine Zeile / nämlich das +=) an einen initialen Ort wie etwa nach InitializeComponent zu stellen.

    Du kannst jetzt Deinen Code erstmal so lassen. Es gäbe zwar viel, was da anzumerken wäre, aber da hätte ich jetzt ein langes Posting vor mir ;-) Das sprengt etwas den Rahmen - es sei denn, Du hättest noch ein konkretes "blockierendes" Problem.

    Vielleicht trotzdem ein paar Dinge zum Projekt als grobe Richtung (sorry, wenn ich nur die negativen Sachen sage -> nimm es als Kritik auf hohem Niveau:-)

    - Die Konfiguration ist bei mir nicht gut beim Anfang gesetzt worden.
      Die sollte automatisch einen typischen Standard annehmen.

    - Die Bedienung ist noch nicht intuitiv genug

    - Menü "Über" normal ganz nach rechts.

    - Eine Kurz-Hilfe einbauen / zum Beispiel ganz rechts oder zusammen mit "Über"

    - Unbedingt ToolTip's über die Buttons machen
      Dort kurz und präzise erklären, was es macht / was zu erwarten ist.

    - die letzte Updatesuche ist nicht Bedienungs-relevant / in ein Sub-Menü oder bei MouseOver / oder kleiner.
      "Weniger ist mehr" in Beziehung auf Übersichtlichkeit.
      Die Bedeutung der IP-Buttons muß noch klarer/intuitiver werden.

    - Die Klassen sind intern nicht genügend gekapselt. Zuviel Code in einer Datei - zu verwoben.
      Man sollte da mehr zusammenfassen und strukturieren.
      Ggf. auch mal später Erweiterungen vorsehen u.a.. Guter Einstieg da oft:

      [Clean Code Developer]
      http://www.drothmaler.de/ccd/CcdWerteSystem.html


    Aber sonst finde ich Dein Programm schon ganz ordentlich.
    So, ich denke ich habe ein wenig Feedback dazu gegeben. 
    Ich denke - wir sollten dann jetzt auch die Frage abschliessen.

    Viel Spaß!

     


    ciao Frank
    Sonntag, 7. November 2010 13:29
  • Ich habe nun was das Problem betrifft eine bessere Lösung gefunden:

    Und zwar habe ich die ListBox entfernt und stattdessen eine ListView eingesetzt. Das hat den Vorteil, das es nicht nur übersichtlicher und Ordentlicher mit den Spalten in der Ausgabe ist, sondern auch das ich den ganzen DrawMode nicht mehr brauche. Jetzt kann man über Forecolor arbeiten. Was wesentlich bequemer als die alte Methode ist.

     

    @T.S.

    Deine Lösung wäre sicherlich auch sehr gut gewesen. Daran habe ich keinerlei Zweifel. Ich fand diesen Weg nun praktischer.

    Sonntag, 7. November 2010 16:23
  • @T.S.
    Deine Lösung wäre sicherlich auch sehr gut gewesen. Daran habe ich keinerlei Zweifel. Ich fand diesen Weg nun praktischer.
    R,
    darf ich dich daran erinnern dass der Titel hier
     "Anwendung wird langsamer und verstopft"
    ist.
    Ich habe exakt dazu und zu deiner Projekt-Datei sofort die direkteste und korrekteste Problemlösung dargestellt.
    Dass du jetzt plötzlich (für alle unvorhersehbar!) ein anderes Control anwendest, hat mit deiner Anfrage technisch nichts mehr zu tun.
    Für alle nachfolgende Leser machst du dies mit der entsprechenden Antwortmarkierung überhaupt nachvollziehbar.
    Beachte, für neue Anliegen kannst du hier auch zusätzliche Antwortmarkierungen vergeben, oder gleich neuen Thread mit spezifischem Thema eröffnen.
    Sonntag, 7. November 2010 18:18
  • Deine Lösung wäre sicherlich auch sehr gut gewesen. Daran habe ich keinerlei Zweifel. Ich fand diesen Weg nun praktischer.

    Eine Diskussion dazu würde "mit meiner Anfrage nichts mehr zu tun haben", daher belasse ich es jetzt einfach dabei. Alle Posts die vorgschlagen waren, sind nun markiert!

     

    Und wie gesagt, an die nachleser des Posts, ich bin von ListBox auf ListView umgestiegen, damit geht es wesentlich leichter! Es erspart einen den mühseligen Umgang mit DrawItem, zudem ist sie übersichtlicher und bequem zu handhaben.

     

    @ F.D.

    Das mit der negativen Kritik ist schon ganz ok, sie ist ja nicht böse gemeint sondern soll unterstützen und in dem Falle nützt mir negative mehr als positive, da sie mir sagt was ich zu verbessern habe.

    Dass das Design nicht das beste in Punkto Übersicht und Handhabung mit Tooltips ist, kann ich durchaus nachvollziehen auch die fehlenden Hilfen, die wollte ich noch reinbringen. Bis jetzt habe ich aber auf Funktion geachtet, weniger auf Design.

    Das mit dem vielen Code ist war, gefällt mir auch nicht, habe aber schon eine Lösung gefunden, wie ich den auslagern kann!

     

     

    Da nun alle Fragen geklärt sind, es sei denn es bestehen noch welche von anderer Seite, würde ich auch vorschlagen die Sache zu beenden.

    Sonntag, 7. November 2010 20:34
  • Alle Posts die vorgschlagen waren, sind nun markiert!


    R,
    und dabei hast du doch insbesondere auch die 'unzutreffendste' Antwort  (ThreadPool)  von allen erwischt,
    welche jetzt rein wegen chronologischer Forumsansicht [im Web] zuoberst steht, folglich alle Nachleser zuerst mal auf Irrwege führt)

    Aber dagegen die allererste (schon nach 12 Minuten!), meine bereits _treffende_ (DrawItem) Antwort (5.Nov 23:01) scheinst du unbedingt ignorieren zu wollen?
      (bedenke, jene Antwort nannte auch schon 2 weitere Probleme in deinem Code!)

    Beachte, ich schreibe hier ab jetzt nur darum so direkt weil du mit deiner (längst widerlegten) Behauptung darauf:
      "Die Zeile mit DrawItem habe ich rausgenommen,
       sie war wohl das überbleibsel von ein paar Experimenten mit dem Codeteil"

    leider schon mal etwas an Glaubwürdigkeit vergeben hast!

    Also, nutze deine Chance und Beurteile die Antworten immer zuerst nach dem, was
     (im Bezug auf den Titel und gezeigten Code-Ausschnitt!)
    deinen Bug kausal verursacht hat, und welche Antwort darauf bereits exakt treffend war.

    Sonntag, 7. November 2010 23:36
  • Hallo RT.,

              > Das mit der negativen Kritik ist schon ganz ok, sie ist ja
              > nicht böse gemeint sondern soll unterstützen und in dem Falle nützt
              > mir negative mehr als positive, da sie mir sagt was ich zu verbessern habe.

    richtig, und es freut mich, dass Du das konstruktiv aufnimmst!
    Das ist ein guter Grundstein für gute Software-Entwicklung.

    viel Spaß weiterhin!

     


    ciao Frank
    Montag, 8. November 2010 06:32