Autor |
Beitrag |
reox
      
Beiträge: 37
|
Verfasst: Di 22.09.09 21:07
Ich muss in einer DataGridView nach einigen Datensätzen suchen. Insgesamt habe ich 910 Zeilen drin, und die Suche wie ich sie programmiert habe braucht dabei etwa 5 sekunden, zulange finde ich... Nun hätte ich gerne gewusst wie ich das ganze verschnellern kann:
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30:
| private void threadFilterNonExistingFiles() { try { toolStripStatusLabel2.Text = "filtert..."; fileGrid.Sort(fileGrid.Columns[4], ListSortDirection.Ascending); int count = fileGrid.RowCount; for (int i = 0; i < count; i++) { string filePath = fileGrid[4, i].Value.ToString(); if (!File.Exists(filePath)) fileGrid.Rows[i].DefaultCellStyle.BackColor = Color.Red; toolStripProgressBar1.PerformStep(); }
} catch (ThreadAbortException) { } catch (Exception e) { Error.log(e); } finally { toolStripProgressBar1.Value = 0; toolStripStatusLabel2.Text = ""; toolStripStatusLabel3.Visible = false; } } |
Außerdem habe ich noch ein Problem mit dem Thread selber. Ich möchte die Filterfunktion abbrechen können, daher ein Button bei dessen Klick folgender Code ausgeführt wird:
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| private void toolStripStatusLabel3_Click(object sender, EventArgs e) { try { filterThread.Suspend(); if (Dialog.MessageBox("Wollen Sie den Vorgang wirklich abbrechen?", MessageBoxButtons.YesNo, Dialog.MessageBoxType.Question) == DialogResult.Yes) { filterThread.Resume(); filterThread.Abort(); refreshDataGrid(); } else filterThread.Resume(); } catch (Exception) { } } |
Nun sagt mit VS2008express das Suspend() und Resume() veraltet sind und ich deshalb Interrupt nehmen soll... Nur hab ich keine Ahnung wie ich das catchen und um Falle eines nicht Abbruches wieder weitermache. Kann mir da jemand ein kurzes Beispiel geben?
|
|
Kha
      
Beiträge: 3803
Erhaltene Danke: 176
Arch Linux
Python, C, C++ (vim)
|
Verfasst: Di 22.09.09 21:42
Du willst auf Controls in einem Nebenthread zugreifen? Das sollte keine 5 Sekunden dauern, sondern eine InvalidOperationException werfen  . Du kannst höchstens die Überprüfung der 910 Dateipfade auslagern (was wahrscheinlich den Großteil der Zeit verschlingt, aber das musst du messen), das DataGridView kannst du nur auf dem GUI-Thread manipulieren.
reox hat folgendes geschrieben : | [...]um Falle eines nicht Abbruches wieder weitermache. Kann mir da jemand ein kurzes Beispiel geben? |
Wie wäre es denn mit dieser Idee: Du hältst den Thread gar nicht erst an, wenn der User auf "Nein" klickt  ?
_________________ >λ=
|
|
reox 
      
Beiträge: 37
|
Verfasst: Di 22.09.09 21:50
mh naja kann man schon, fand das so aber irgendwie schöner
aber mal so programmdesign-technisch: sollte ich im prinzip nachdem das GUI aufgebaut ist einen Haupt-Thread Starten und dann aus dem die einzelnen zB filter Threads starten? Oder warum sollte es eine InvalidOperationException geben?
Auf die ganzen GUI Teile dann per delegaten zugreifen oder wie?
|
|
Kha
      
Beiträge: 3803
Erhaltene Danke: 176
Arch Linux
Python, C, C++ (vim)
|
Verfasst: Di 22.09.09 21:55
reox hat folgendes geschrieben : | mh naja kann man schon, fand das so aber irgendwie schöner  |
Uh... von mir aus  .
reox hat folgendes geschrieben : | aber mal so programmdesign-technisch: sollte ich im prinzip nachdem das GUI aufgebaut ist einen Haupt-Thread Starten und dann aus dem die einzelnen zB filter Threads starten? |
Der GUI-Thread ist ja schon gestartet, darum musst du dich nicht mehr kümmern.
reox hat folgendes geschrieben : | Oder warum sollte es eine InvalidOperationException geben? |
Zitat: | Access to Windows Forms controls is not inherently thread safe. If you have two or more threads manipulating the state of a control, it is possible to force the control into an inconsistent state. Other thread-related bugs are possible as well, including race conditions and deadlocks. It is important to ensure that access to your controls is done in a thread-safe way.
The .NET Framework helps you detect when you are accessing your controls in a manner that is not thread safe. When you are running your application in the debugger, and a thread other than the one which created a control attempts to call that control, the debugger raises an InvalidOperationException with the message, "Control control name accessed from a thread other than the thread it was created on." |
reox hat folgendes geschrieben : | Auf die ganzen GUI Teile dann per delegaten zugreifen oder wie? |
Über Control.(Begin)Invoke, jupp. Brauchst du hier aber höchstens für die ProgressBar, würde ich sagen. Und dafür könntest du einen BackgroundWorker einsetzen, mit dem ersparst du dir die Invokes.
_________________ >λ=
|
|
reox 
      
Beiträge: 37
|
Verfasst: Di 22.09.09 22:06
ok ich hab das bisher nur mit textfelder usw gemacht, wie mach ich das denn dann konkret für die methode PerformStep()?
wie ich das kenne:
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8:
| delegate void UpdateLabel(string s); private void updateLabel(string s){ label.Text = s; }
BeginInvoke(new UpdateLabel(updateLabel), "hallo welt"); |
etwa so?
C#-Quelltext 1: 2: 3: 4:
| delegate void UpdatePG(); BeginInvoke(new UpdatePG(progressBar.PerformStep)); |
achso und wegen dem checken: ich hab auch noch eine andere methode die auch filtert, allerdings Daten und die braucht ähnlich lange...
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32:
| private void threadFilterOldFiles() { try { toolStripStatusLabel2.Text = "filtert..."; fileGrid.Sort(fileGrid.Columns[2], ListSortDirection.Ascending); int count = fileGrid.RowCount; for (int i = 0; i < count; i++) { int year = Int32.Parse(fileGrid[2, i].Value.ToString().Substring(6, 4)); int month = Int32.Parse(fileGrid[2, i].Value.ToString().Substring(3, 2)); int day = Int32.Parse(fileGrid[2, i].Value.ToString().Substring(0, 2));
if (new DateTime(year, month, day).CompareTo(DateTime.Today.AddYears(-1)) <= 0) fileGrid.Rows[i].DefaultCellStyle.BackColor = Color.Red; toolStripProgressBar1.PerformStep(); } } catch (ThreadAbortException) { } catch (Exception x) { Error.log(x); } finally { toolStripProgressBar1.Value = 0; toolStripStatusLabel2.Text = ""; toolStripStatusLabel3.Visible = false; } } |
hab grad keine IDE da, kanns also erst frühestens morgen in der arbeit testen 
|
|
Kha
      
Beiträge: 3803
Erhaltene Danke: 176
Arch Linux
Python, C, C++ (vim)
|
Verfasst: Di 22.09.09 23:05
reox hat folgendes geschrieben : | achso und wegen dem checken: ich hab auch noch eine andere methode die auch filtert, allerdings Daten und die braucht ähnlich lange... |
Also liegt es rein am DataGridView und ein dedizierter Thread bringt dir überhaupt nichts  .
Ist schon etwas länger her, dass ich das letzte Mal Winforms benutzt habe, aber als ich vor einem ähnlichen Problem stand, habe ich nicht im Voraus den Rows ihre Farbe zugewiesen, sondern "on Demand" im RowPrePaint berechnet und per PaintCellsBackground gezeichnet (afaik).
_________________ >λ=
|
|
reox 
      
Beiträge: 37
|
Verfasst: Mi 23.09.09 11:13
ok ich konnte die geschwindigkeit extrem verbessern indem ich das mit einem delegaten und asycronem update gemacht habe:
C#-Quelltext 1:
| BeginInvoke(new UpdateProgressbar(toolStripProgressBar1.PerformStep)); |
Nun ist aber das Problem das der zu schnell durchrennt und daher manchmal die Progressbar wieder von vorne anfängt und dann ein paar schritte draufgezählt werden. Kann ich sowas verhinden? isses da gescheit eine Methode zu schreiben in der ich überprüfe ob der thread schon aus ist und dann erst die progressbar weitersetze? Hab mit PGbars eigentlich noch nie wirklich ernsthaft gearbeitet 
|
|
Kha
      
Beiträge: 3803
Erhaltene Danke: 176
Arch Linux
Python, C, C++ (vim)
|
Verfasst: Mi 23.09.09 17:49
Dann eben Invoke  . Damit hält der Thread solange an, bis der Delegate ausgeführt ist.
_________________ >λ=
|
|
reox 
      
Beiträge: 37
|
Verfasst: Sa 26.09.09 15:03
mh ja aber dann dauert es wieder genau so lange wie vorher... alles doof :c
|
|
Kha
      
Beiträge: 3803
Erhaltene Danke: 176
Arch Linux
Python, C, C++ (vim)
|
Verfasst: Sa 26.09.09 18:22
Wenn das Programm durchs ProgressBar-Updaten ausgelastet wird, rufst du Invoke eindeutig zu oft auf. Wahrscheinlich sind die winzigen Fortschritte nicht einmal sichtbar.
Ansonsten habe ich langsam den Überblick über deinen aktuellen Code verloren, da müsstest du mir auf die Sprünge helfen.
_________________ >λ=
|
|
reox 
      
Beiträge: 37
|
Verfasst: Mo 28.09.09 15:44
Ich hab jetzt den Step auf 50 gesetzt und Invoke auch nur noch alle 50 Rows... Die Geschwindigkeit ist jetzt zwar nicht so hoch wie mit BeginInvoke, aber ich bekomme zumindest keine Fehler mehr, also zuviel usw...
|
|
|