wpf - Opdatering af brugergrænsefladen fra flere baggrundstråde

Indlæg af Hanne Mølgaard Plasc

Problem



Spørgsmålet her er lidt abstrakt. Vi ved alle, for en baggrundstråd for at opdatere nogle brugergrænseelementer.


Dispatcher.Invoke()


er den eneste mulighed (er det?). Dispatcher.Invoke () i sig selv delegerer opdateringsopgaven til brugergrænsefladen. I betragtning af scenarier hvor:



  • En baggrundstråd opdaterer for ofte en brugerflade.

  • Mange tråd opdaterer samme brugergrænseflade.



Dispatcher-objektet fortsætter med at delegere opdateringsopgaven til brugergrænsefladen, og brugergrænsefladen kan gå langsomt. Hvad kan være en mulig løsning? Hvordan kunne vi løse et sådant problem i Windows Forms , hvor trådemodellen lignede WPF? Indeholder WPF nogen anden gevindteknik?


hilsen,

Bedste reference


Først og fremmest, hvorfor er der behov for at opdatere brugergrænsefladen, at hyppigt det menneskelige øje ikke vil bemærke, ideelt, selvom nogen fremskridt er opdateret med et mellemrum på et sekund, er det acceptabelt. For eksempel hvis du skriver en fil, og du sandsynligvis skriver 4K bytes hver 30 millisekunder, vil menneskets øje ikke mærke og vi bryr os ikke om ydeevne på skærmen i millisekunder.


Ikke alene vil du gøre brugergrænsefladen optaget, men Dispatcher.Invoke vil også blokere din anden tråd, indtil udførelsen er færdig, Dispatcher.BeginInvoke vil ikke blokere din anden tråd.


UI Thread vil sandsynligvis afslutte opdateringer om få millisekunder, hvis det bare opdaterer få mærker eller fremskridt på skærmen.


Hverken WPF eller nogen anden platform kan give en bedre måde, fordi brugergrænseflade er en meget kompleks og tillader adgang fra flere tråde kan føre til deadlocks så ofte, at appen kan blive ikke-responsiv. Dette er grunden til, at hver platform, det være sig java, objektiv-c eller en hvilken som helst brugergrænseflade, skal du opdatere brugergrænsefladen kun i brugergrænsefladen.


Der er dog en måde i WPF at også oprette flere brugergrænseflader pr. Vindue, men det er også ganske komplekst. Spil osv. Bruger noget, der hedder dobbelt buffering, hvor de arbejder på en buffer i baggrunden i separat tråd, mens tidligere buffer stadig opdateres på skærmen.

Andre referencer 1


Hvis du overbelaster GUI-trådens indgangskø ved at sende meddelelser, (APC'er, delegerede, uanset), hurtigere end de kan håndteres, vil der være problemer uanset WPF/Forms/uanset.


I de tilfælde, hvor flere GUI-stater opdateres så ofte, at postering hver ændring vil overbelaste køen og/eller resultere i et display, der ændrer sig for hurtigt til at være læsbart, er det almindeligt, at de ikke-GUI-tråde kan gemme deres nyeste data i delte objekter/s og for GUI-tråden for at vise dataene ved hjælp af en timer med mere rimelige intervaller.


Hvis alle data skal vises uden tab (f.eks. Et GUI-memo eller HTML-renderer skal vise alt sendt), kan det være nødvendigt med passende flowstyring via objektpuljer og/eller dovne postering af data for at forhindre overbelastning af meddelelseskø .


'Problemet her er lidt abstrakt' - ikke det abstrakte. Jeg har ramt dette problem mange gange med optaget apps. I mine ting har langvarig indgangskø overbelastning tendens til at resultere i deadlock, fordi alle genstande fra min inter-thread comms pool sidder fast i meddelelser, der ikke håndteres og frigives til poolen, fordi GUI'en er blokeret - forsøger at få en genstand fra den tomme pool: ((

Andre referencer 2


Enkelt, brug ikke Invoke til at opdatere brugergrænsefladen. I stedet har medarbejdertråden offentliggjort de data, der skal 'sendes til brugergrænsefladen' i en fælles datastruktur som en kø eller en liste og har brugergrænsefladen tråd undersøgelse for det på et bestemt interval. Dette har flere fordele.



  • Det bryder den stramme kobling mellem brugergrænsefladen og arbejdstråden, som Invoke pålægger.

  • UI-tråden bliver dikteret, når brugergrænsefladen kontrolleres bliver opdateret ... sådan skal det være, når du virkelig tænker på det.

  • Der er ingen risiko for at overskride UI-meddelelseskøen eller sultne ud andre meddelelser, som det ville være tilfældet, hvis Invoke eller BeginInvoke blev brugt fra arbejdstrådens tråd.

  • Arbejdstråd behøver ikke at vente på et svar fra brugergrænsefladen som det ville være tilfældet med Invoke.

  • Du får mere gennemstrømning både på brugergrænsefladen og arbejdstagerne.

  • Invoke og BeginInvoke er dyre operationer.



Jeg ved, at jeg har det hele tiden, men der er virkelig bedre alternativer til Invoke i mange situationer. Marshaling teknikker som Invoke er måde overbrugt.