Entwickler-Ecke
WinForms - Formular trotz Multithreading nicht bedienbar durch Invokes
AXMD - Di 15.04.08 18:41
Titel: Formular trotz Multithreading nicht bedienbar durch Invokes
Hallo!
Ich beschäftige mich seit kurzem mit Multithreading in .NET und habe testweise ein Programm geschrieben, das Dateien in einem separaten Thread rekursiv in einem vorgegebenen Ordner sucht und das Ergebnis in einer ListBox ausgibt. Hier der relevante Codeausschnitt des Threads:
C#-Quelltext
1: 2: 3: 4: 5: 6:
| FilesFoundListBox.Invoke(new VoidCall(FilesFoundListBox.BeginUpdate)); FilesFoundListBox.Invoke(new VoidCall(FilesFoundListBox.Items.Clear)); SetText(FilesFoundGroupBox, "Files found"); UnfilteredFileList = ... FilesFoundListBox.Invoke(new ObjectArrayParamCall(FilesFoundListBox.Items.AddRange), new object[] { UnfilteredFileList }); FilesFoundListBox.Invoke(new VoidCall(FilesFoundListBox.EndUpdate)); |
wobei ich für die Invoke-Aufrufe noch diese beiden Delegates deklariert habe:
C#-Quelltext
1: 2:
| delegate void VoidCall(); delegate void ObjectArrayParamCall(object[] Param); |
Wenn ich jetzt beispielsweise C:\ durchsuchen lasse, dauert das sehr lange, aber ich kann während die Suche läuft das Formular wie gewohnt bedienen. Sobald allerdings FilesFoundListBox.Items.AddRange aufgerufen wird, reagiert das Hauptformular nicht mehr und wird für ca. eine Minute weiß. Da ich Invokes verwende ist das prinzipiell logisch, da der Hauptthread AddRange ausführt.
Nun meine Frage: wie kann ich dennoch dafür sorgen, dass mein Formular während des Hinzufügens der Items in die ListBox bedienbar bleibt? Gibt es eventuell Alternativlösungen?
AXMD
Kha - Mi 16.04.08 10:27
Na dann würde ich einfach die Items einzeln hinzufügen ;) . Dann lässt sich (ohne Begin/EndUpdate) auch das (flackernde) Befüllen beobachten. Irgendwann werden aber die tausend Invoke-Aufrufe selbst natürlich zum Flaschenhals, man könnte also stattdessen z.B. immer 10 Items auf einmal zur ListBox schicken. Oder im Nebenthread eine Queue befüllen und diese dann im Hauptthread mit einem 100ms-Timer abarbeiten... naja, wir wollen mal nicht übertreiben :mrgreen: .
PS: Vielleicht ist hier BeginInvoke (asynchron) besser geeignet, damit wartet der Such-Thread nicht mehr auf die GUI-Aktionen in den Invokes.
AXMD - Mi 16.04.08 11:27
Khabarakh hat folgendes geschrieben: |
Na dann würde ich einfach die Items einzeln hinzufügen ;) . |
Das erhöht doch die Dauer zusätzlich
Khabarakh hat folgendes geschrieben: |
Dann lässt sich (ohne Begin/EndUpdate) auch das (flackernde) Befüllen beobachten. |
Das halte ich nicht für sinnvoll, vor allem weil das Flackern störend ist und unnötig viel Zeit kostet
Khabarakh hat folgendes geschrieben: |
Irgendwann werden aber die tausend Invoke-Aufrufe selbst natürlich zum Flaschenhals, man könnte also stattdessen z.B. immer 10 Items auf einmal zur ListBox schicken. |
Das ändert aber auch nichts an der Tatsache, dass das Formular in der Zwischenzeit nicht reagiert
Khabarakh hat folgendes geschrieben: |
Vielleicht ist hier BeginInvoke (asynchron) besser geeignet, damit wartet der Such-Thread nicht mehr auf die GUI-Aktionen in den Invokes. |
Es spielt keine Rolle, ob der Nebenthread wartet oder nicht - es geht darum, dass das Hauptformualar bedienbar bleibt.
AXMD
Christian S. - Mi 16.04.08 11:40
AXMD hat folgendes geschrieben: |
Khabarakh hat folgendes geschrieben: | Na dann würde ich einfach die Items einzeln hinzufügen ;) . |
Das erhöht doch die Dauer zusätzlich |
Wenn Du eine Aktualisierung der GUI willst, braucht das nunmal Rechenzeit. Eine eingefrorene GUI wird immer weniger Rechenzeit brauchen, als eine, die reagiert. Erinnere Dich an
Application.ProcessMessages aus den Delphi-Zeiten ;-)
Du schreibst zwar, die GUI hänge bei AddRange, aber es dürfte eher der Aufruf von EndUpdate sein, oder? Denn erst dann wird die GUI aktualisiert. Und zu dem Zeitpunkt wird halt ein großer Batzen an Items auf einmal in die Listbox gepackt und das blockiert. Ich sehe auch nur die Möglichkeit, immer nur ein paar Items in die Listbox zu packen , damit die GUI zwischendurch Zeit hat, sich zu Aktualisieren.
In der WPF hätte man die Möglichkeit, bei Invoke noch eine Priorität mitzugeben, aber das ist mir aus WinForms nicht bekannt.
AXMD - Mi 16.04.08 12:27
Dann werde ich heute Abend mal versuchen, die Listbox 10-Items-weise zu befüllen. Alternativ schwebt mir eine ListView vor (ist die eventuell schneller?) - habe aber hier in der Arbeit keine Zeit, um das zu testen.
Danke für deine Antwort
AXMD
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!