Megosztás a következőn keresztül:


Eseményalapú aszinkron minta áttekintése

Azok az alkalmazások, amelyek egyszerre sok feladatot hajtanak végre, mégis reagálnak a felhasználói interakciókra, gyakran több szálat használó kialakítást igényelnek. A System.Threading névtér biztosítja a nagy teljesítményű többszálú alkalmazások létrehozásához szükséges összes eszközt, de ezeknek az eszközöknek a hatékony használata jelentős tapasztalatot igényel a többszálú szoftverfejlesztés terén. A viszonylag egyszerű, többszálú alkalmazásokhoz az BackgroundWorker összetevő egyszerű megoldást kínál. Kifinomultabb aszinkron alkalmazásokhoz érdemes lehet olyan osztályt implementálni, amely megfelel az eseményalapú aszinkron mintának.

Az eseményalapú aszinkron minta elérhetővé teszi a többszálú alkalmazások előnyeit, miközben elrejti a többszálas kialakításban rejlő összetett problémákat. Az ezt a mintát támogató osztály használatával a következőket teheti lehetővé:

  • Időigényes feladatokat hajt végre, például letöltéseket és adatbázis-műveleteket a háttérben, az alkalmazás megszakítása nélkül.

  • Egyszerre több műveletet hajt végre, és értesítést kap, ha mindegyik befejeződik.

  • Várjon, amíg az erőforrások elérhetővé válnak az alkalmazás leállítása (blokkolása) nélkül.

  • Kommunikáljon a függőben lévő aszinkron műveletekkel a jól ismert esemény- és delegálási modell használatával. Az eseménykezelők és a meghatalmazottak használatáról további információt az Események című témakörben talál.

Az eseményalapú aszinkron mintát támogató osztály egy vagy több MetódusnévAsync nevű metódussal rendelkezik. Ezek a metódusok tükrözhetik a szinkron verziókat, amelyek ugyanazt a műveletet hajtják végre az aktuális szálon. Az osztály rendelkezhet MethodName Completed eseménysel is, és lehet, hogy methodNameAsyncCancel (vagy egyszerűen CancelAsync) metódussal rendelkezik.

PictureBox egy tipikus összetevő, amely támogatja az eseményalapú aszinkron mintát. A rendszerképet szinkron módon töltheti le a metódus meghívásával Load , de ha a rendszerkép nagy, vagy ha a hálózati kapcsolat lassú, az alkalmazás a letöltési művelet befejezéséig nem válaszol, és a hívás Load visszatér.

Ha azt szeretné, hogy az alkalmazás továbbra is futjon a kép betöltése közben, meghívhatja a LoadAsync metódust, és kezelheti az LoadCompleted eseményt, ugyanúgy, mint bármely más eseményt. Amikor meghívja a LoadAsync metódust, az alkalmazás továbbra is futni fog, amíg a letöltés egy külön szálon (a háttérben) folytatódik. A rendszer meghívja az eseménykezelőt, amikor a képbetöltési művelet befejeződött, és az eseménykezelő megvizsgálhatja a AsyncCompletedEventArgs paramétert annak megállapításához, hogy a letöltés sikeresen befejeződött-e.

Az eseményalapú aszinkron minta megköveteli az aszinkron művelet megszakítását, és a vezérlő a metódusával támogatja ezt a PictureBox követelményt CancelAsync . A hívás CancelAsync kérést küld a függőben lévő letöltés leállítására, és a feladat megszakítása után az LoadCompleted esemény létrejön.

Figyelemfelhívás

Lehetséges, hogy a letöltés a kéréssel megegyező módon CancelAsync fejeződik be, ezért Cancelled előfordulhat, hogy nem tükrözi a lemondásra vonatkozó kérést. Ezt nevezik versenyfeltételnek, és gyakori probléma a többszálú programozásban. A többszálas programozással kapcsolatos problémákról további információt a Felügyelt szálkezelés ajánlott eljárásai című témakörben talál.

Az eseményalapú aszinkron minta jellemzői

Az eseményalapú aszinkron minta számos formát ölthet az adott osztály által támogatott műveletek összetettségétől függően. A legegyszerűbb osztályok egyetlen MethodNameAsync metódussal és egy megfelelő MethodNameCompleted eseménysel rendelkezhetnek. Az összetettebb osztályok több MethodNameAsync metódussal is rendelkezhetnek, amelyek mindegyike rendelkezik megfelelő MethodNameCompleted eseménysel, valamint ezeknek a metódusoknak a szinkron verzióival. Az osztályok opcionálisan támogathatják a lemondást, a folyamatjelentést és a növekményes eredményeket az egyes aszinkron metódusokhoz.

Az aszinkron metódus több függőben lévő hívást (több egyidejű hívás) is támogathat, így a kód tetszőleges számú alkalommal meghívhatja, mielőtt más függőben lévő műveleteket hajt végre. A helyzet megfelelő kezelése esetén előfordulhat, hogy az alkalmazásnak nyomon kell követnie az egyes műveletek befejezését.

Példák az eseményalapú aszinkron mintára

Az SoundPlayer összetevők az PictureBox eseményalapú aszinkron minta egyszerű implementációit jelölik. Az WebClient összetevők az BackgroundWorker eseményalapú aszinkron minta összetettebb implementációit képviselik.

Az alábbiakban egy példaosztály-deklaráció látható, amely megfelel a mintának:

Public Class AsyncExample  
    ' Synchronous methods.  
    Public Function Method1(ByVal param As String) As Integer
    Public Sub Method2(ByVal param As Double)
  
    ' Asynchronous methods.  
    Overloads Public Sub Method1Async(ByVal param As String)
    Overloads Public Sub Method1Async(ByVal param As String, ByVal userState As Object)
    Public Event Method1Completed As Method1CompletedEventHandler  
  
    Overloads Public Sub Method2Async(ByVal param As Double)
    Overloads Public Sub Method2Async(ByVal param As Double, ByVal userState As Object)
    Public Event Method2Completed As Method2CompletedEventHandler  
  
    Public Sub CancelAsync(ByVal userState As Object)
  
    Public ReadOnly Property IsBusy () As Boolean  
  
    ' Class implementation not shown.  
End Class  
public class AsyncExample  
{  
    // Synchronous methods.  
    public int Method1(string param);  
    public void Method2(double param);  
  
    // Asynchronous methods.  
    public void Method1Async(string param);  
    public void Method1Async(string param, object userState);  
    public event Method1CompletedEventHandler Method1Completed;  
  
    public void Method2Async(double param);  
    public void Method2Async(double param, object userState);  
    public event Method2CompletedEventHandler Method2Completed;  
  
    public void CancelAsync(object userState);  
  
    public bool IsBusy { get; }  
  
    // Class implementation not shown.  
}  

A fiktív AsyncExample osztály két metódussal rendelkezik, amelyek mindegyike támogatja a szinkron és az aszinkron hívásokat. A szinkron túlterhelések bármilyen metódushíváshoz hasonlóan viselkednek, és végrehajtják a műveletet a hívószálon; ha a művelet időigényes, a hívás visszaérkezése jelentős késéssel járhat. Az aszinkron túlterhelések elindítják a műveletet egy másik szálon, majd azonnal visszatérnek, lehetővé téve a hívó szál folytatását, miközben a művelet "a háttérben" fut.

Aszinkron metódus túlterhelései

Az aszinkron műveleteknek két túlterhelése lehet: az egyszeri meghívás és a többszörös meghívás. Ezt a két űrlapot a metódusaik alapján különböztetheti meg: a többszörös meghívású űrlapnak van egy további, úgynevezett paramétere userState. Ez az űrlap lehetővé teszi, hogy a kód többször is hívjon Method1Async(string param, object userState) anélkül, hogy várnia kell a függőben lévő aszinkron műveletek befejezésére. Ha viszont egy korábbi hívás befejezése előtt próbál hívást kezdeményezni Method1Async(string param) , a metódus egy InvalidOperationException.

A userState többszörös meghívású túlterhelések paramétere lehetővé teszi az aszinkron műveletek megkülönböztetést. Minden egyes híváshoz Method1Async(string param, object userState)egyedi értéket (például GUID- vagy kivonatkódot) ad meg, és ha minden művelet befejeződött, az eseménykezelő meghatározhatja, hogy a művelet melyik példánya indította el a befejezési eseményt.

Függőben lévő műveletek nyomon követése

Ha a többszörös meghívás túlterheléseit használja, a kódnak nyomon kell követnie a userState függőben lévő tevékenységek objektumait (feladatazonosítóit). Minden egyes híváshoz Method1Async(string param, object userState)általában létrehoz egy új, egyedi userState objektumot, és hozzáadja egy gyűjteményhez. Amikor az objektumnak userState megfelelő feladat létrehozza a befejezési eseményt, a befejezési módszer implementációja megvizsgálja AsyncCompletedEventArgs.UserState és eltávolítja azt a gyűjteményből. Ezzel a módszerrel a userState paraméter egy tevékenységazonosító szerepét veszi át.

Feljegyzés

Ügyeljen arra, hogy egyedi értéket userState adjon a többszörös meghívású túlterhelések hívásaiban. A nem egyedi feladatazonosítók miatt az aszinkron osztály egy ArgumentException.

Függőben lévő műveletek megszakítása

Fontos, hogy a befejezés előtt bármikor le lehessen mondani az aszinkron műveleteket. Az eseményalapú aszinkron mintát megvalósító osztályok rendelkeznek metódussal CancelAsync (ha csak egy aszinkron metódus van) vagy egy MethodNameAsyncCancel metódussal (ha több aszinkron metódus is létezik).

A több meghívást lehetővé tevő metódusok egy userState paramétert használnak, amely az egyes tevékenységek élettartamának nyomon követésére használható. CancelAsync egy paramétert userState vesz fel, amely lehetővé teszi bizonyos függőben lévő tevékenységek megszakítását.

Azok a metódusok, amelyek egyszerre csak egyetlen függőben lévő műveletet támogatnak, például Method1Async(string param), nem törölhetők.

Folyamat Frissítések és növekményes eredmények fogadása

Az eseményalapú aszinkron mintához igazodó osztály opcionálisan eseményt biztosíthat az előrehaladás és a növekményes eredmények nyomon követéséhez. Ez általában el lesz nevezve ProgressChanged vagy MethodNameProgressChanged, és a megfelelő eseménykezelő egy paramétert ProgressChangedEventArgs fog használni.

Az esemény eseménykezelője ProgressChanged megvizsgálhatja a ProgressChangedEventArgs.ProgressPercentage tulajdonságot annak megállapításához, hogy egy aszinkron tevékenység hány százaléka lett befejezve. Ez a tulajdonság 0 és 100 közötti lehet, és egy ValueProgressBar. Ha több aszinkron művelet is függőben van, a ProgressChangedEventArgs.UserState tulajdonság segítségével megkülönböztetheti, hogy melyik művelet jelenti az előrehaladást.

Egyes osztályok aszinkron műveletek folytatásaként növekményes eredményeket jelenthetnek. Ezek az eredmények egy olyan osztályban lesznek tárolva, amely származik ProgressChangedEventArgs , és tulajdonságokként jelennek meg a származtatott osztályban. Ezeket az eredményeket az esemény eseménykezelőjében ProgressChanged érheti el, ugyanúgy, mint a tulajdonságot ProgressPercentage . Ha több aszinkron művelet van függőben, a UserState tulajdonság segítségével megkülönböztetheti, hogy melyik művelet jelent növekményes eredményeket.

Lásd még