Dobrý den, pane Langer, pojďme se podívat pod kapotu. Srdce každé Windows aplikace s uživatelským rozhraním je tzv. smyčka zpráv (Message Loop). Toto je zjednodušeně řečeno nekonečný cyklus Do...Loop, který nedělá nic jiného, než že přijímá Windows zprávy (Windows Message, WM_*) a odesílá je ke zpracování příslušným metodám (WndProc), ve kterých se již vyvolávají patřičné události (Button.Click). Jak už jsem na tomto webu kdesi zmiňoval, tak Windows zpráv jsou řádově stovky a slouží ke všem možným účelům, pro naše potřeby zejména k aktualizaci ovládacích prvků (vykreslování) a upozorňování na vstupy z klávesnice a myši. Při spuštění aplikace se smyčka zpráv rozjede právě v hlavním vlákně aplikace (po spuštění aplikace vlastně jediném). Následující kód velmi zjednodušeně představuje schéma smyčky zpráv:
Public Module MainModule()
Public Sub Main()
'GetMessage je funkce Windows API pro vyzvednutí Windows
'zprávy z fronty zpráv.
While GetMessage(...)
'Odeslat zprávu ke zpracování (do WndProc)
End While
End Sub
End Module
Vzhledem k tomu, že tento nekonečný cyklus neustále běží po dobu spuštění aplikace a tím pádem se nonstop zpracovávají Windows zprávy, máme pocit, že aplikace běží plynule (překreslování uživatelského rozhraní, reagování na vstupy z klávesnice a myši). Řečnická otázka: Co se stane, když tomuto cyklu postavíme do cesty nějakou náročnou operaci, například načítání dat ze souboru?
Public Module MainModule()
Public Sub Main()
'GetMessage je funkce Windows API pro vyzvednutí Windows
'zprávy z fronty zpráv.
While GetMessage(...)
'Odeslat zprávu ke zpracování (do WndProc)
'Načítání ze souboru je časově náročná operace, která
'zdržuje smyčku zpráv a způsobuje zamrznutí aplikace.
Dim lines = IO.File.ReadAllLines(...)
End While
End Sub
End Module
Odpověď: Smyčka zpráv se pozastaví na dobu, než bude tato náročná operace dokončena a toto je právě důvod proč aplikace zamrzne, pokud náročnou operaci nespustíte ve vlastním vlákně, nezávisle na hlavním vlákně ve kterém běží smyčka zpráv. Co způsobí DoEvents()? Metoda Application.DoEvents() neudělá nic jiného, než že v okamžiku jejího zavolání zpracuje všechny Windows zprávy čekající ve frontě. Z hlediska uživatele aplikace to vypadá jako velmi vláčné, táhlé a pomalu reagující uživatelské rozhraní, které občas neodpovídá. Pokud tedy chceme psát aplikace profesionálně, necháme hlavní vlákno na pokoji ať se věnuje zpracování Windows zpráv a veškerou časově náročnou činnost přesuneme do vlastních vláken. Doufám že jsem do tohoto problému vnesl alespoň trochu světla.
|