Overzicht van Asynchroon patroon op basis van gebeurtenissen
Toepassingen die tegelijkertijd veel taken uitvoeren, maar reageren op gebruikersinteractie, vereisen vaak een ontwerp dat meerdere threads gebruikt. De System.Threading naamruimte biedt alle hulpprogramma's die nodig zijn voor het maken van multithreaded-toepassingen met hoge prestaties, maar het gebruik van deze hulpprogramma's vereist effectief aanzienlijke ervaring met multithreaded software-engineering. Voor relatief eenvoudige multithreaded-toepassingen biedt het BackgroundWorker onderdeel een eenvoudige oplossing. Voor geavanceerdere asynchrone toepassingen kunt u overwegen om een klasse te implementeren die voldoet aan het Asynchrone Asynchrone patroon op basis van gebeurtenissen.
Het Asynchrone patroon op basis van gebeurtenissen maakt de voordelen van multithreaded toepassingen beschikbaar terwijl veel van de complexe problemen worden verborgen die inherent zijn aan een multithreaded-ontwerp. Als u een klasse gebruikt die dit patroon ondersteunt, kunt u het volgende doen:
Voer tijdrovende taken uit, zoals downloads en databasebewerkingen, 'op de achtergrond', zonder uw toepassing te onderbreken.
Voer meerdere bewerkingen tegelijk uit en ontvang meldingen wanneer elke bewerking is voltooid.
Wacht tot er resources beschikbaar zijn zonder uw toepassing te stoppen ('blokkeren').
Communiceer met asynchrone bewerkingen die in behandeling zijn met behulp van het vertrouwde model voor gebeurtenissen en gemachtigden. Zie Gebeurtenissen voor meer informatie over het gebruik van gebeurtenis-handlers en gemachtigden.
Een klasse die het Asynchrone patroon op basis van gebeurtenissen ondersteunt, heeft een of meer methoden met de naam MethodNameAsync. Deze methoden kunnen synchrone versies spiegelen, die dezelfde bewerking uitvoeren op de huidige thread. De klasse kan ook een MethodNameCompleted-gebeurtenis hebben en mogelijk een MethodNameAsyncCancel-methode (of gewoon CancelAsync).
PictureBox is een typisch onderdeel dat ondersteuning biedt voor het Asynchrone patroon op basis van gebeurtenissen. U kunt een installatiekopieën synchroon downloaden door de methode aan te roepen Load , maar als de installatiekopieën groot zijn of als de netwerkverbinding traag is, reageert uw toepassing niet meer totdat de downloadbewerking is voltooid en de aanroep om terug te Load keren.
Als u wilt dat uw toepassing actief blijft terwijl de installatiekopieën worden geladen, kunt u de LoadAsync methode aanroepen en de LoadCompleted gebeurtenis afhandelen, net zoals u andere gebeurtenissen zou afhandelen. Wanneer u de LoadAsync methode aanroept, blijft uw toepassing actief terwijl de download wordt uitgevoerd op een afzonderlijke thread ('op de achtergrond'). Uw gebeurtenis-handler wordt aangeroepen wanneer de bewerking voor het laden van afbeeldingen is voltooid en uw gebeurtenis-handler kan de AsyncCompletedEventArgs parameter onderzoeken om te bepalen of het downloaden is voltooid.
Het Asynchrone patroon op basis van gebeurtenissen vereist dat een asynchrone bewerking kan worden geannuleerd en het PictureBox besturingselement ondersteunt deze vereiste met de CancelAsync bijbehorende methode. Bij het aanroepen CancelAsync wordt een aanvraag ingediend om het downloaden in behandeling te stoppen en wanneer de taak wordt geannuleerd, wordt de LoadCompleted gebeurtenis gegenereerd.
Let op
Het is mogelijk dat de download wordt voltooid, net zoals de CancelAsync aanvraag wordt gedaan, dus Cancelled kan het niet overeenkomen met de aanvraag om te annuleren. Dit wordt een racevoorwaarde genoemd en is een veelvoorkomend probleem bij multithreaded programmeren. Zie Aanbevolen procedures voor beheerde threading voor meer informatie over problemen met programmeren met meerdere threads.
Kenmerken van het Asynchrone patroon op basis van gebeurtenissen
Het Asynchrone patroon op basis van gebeurtenissen kan verschillende vormen aannemen, afhankelijk van de complexiteit van de bewerkingen die door een bepaalde klasse worden ondersteund. De eenvoudigste klassen kunnen één MethodNameAsync-methode en een bijbehorende MethodNameCompleted-gebeurtenis hebben. Complexere klassen kunnen verschillende MethodNameAsync-methoden hebben, elk met een bijbehorende MethodNameCompleted-gebeurtenis, evenals synchrone versies van deze methoden. Klassen kunnen optioneel ondersteuning bieden voor annulering, voortgangsrapportage en incrementele resultaten voor elke asynchrone methode.
Een asynchrone methode kan ook ondersteuning bieden voor meerdere aanroepen die in behandeling zijn (meerdere gelijktijdige aanroepen), zodat uw code deze een willekeurig aantal keren kan aanroepen voordat andere in behandeling zijnde bewerkingen worden voltooid. Voor het correct afhandelen van deze situatie kan het nodig zijn dat uw toepassing de voltooiing van elke bewerking bijhoudt.
Voorbeelden van het Asynchrone patroon op basis van gebeurtenissen
De SoundPlayer onderdelen vertegenwoordigen PictureBox eenvoudige implementaties van het Asynchrone patroon op basis van gebeurtenissen. De WebClient en BackgroundWorker onderdelen vertegenwoordigen complexere implementaties van het Asynchrone patroon op basis van gebeurtenissen.
Hieronder ziet u een voorbeeld van een klassedeclaratie die voldoet aan het patroon:
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.
}
De fictieve AsyncExample
klasse heeft twee methoden, die beide synchrone en asynchrone aanroepen ondersteunen. De synchrone overbelastingen gedragen zich als elke methodeaanroep en voeren de bewerking uit op de aanroepende thread; als de bewerking tijdrovend is, kan er een merkbare vertraging optreden voordat de oproep wordt geretourneerd. De asynchrone overbelasting start de bewerking op een andere thread en keert vervolgens onmiddellijk terug, zodat de aanroepende thread kan doorgaan terwijl de bewerking 'op de achtergrond' wordt uitgevoerd.
Overbelasting van asynchrone methoden
Er zijn mogelijk twee overbelastingen voor de asynchrone bewerkingen: eenmalige aanroep en meervoudige aanroep. U kunt deze twee formulieren onderscheiden door hun methodehandtekeningen: het formulier voor meervoudige aanroep heeft een extra parameter met de naam userState
. Met dit formulier kunt u uw code meerdere keren aanroepen Method1Async(string param, object userState)
zonder te wachten tot eventuele asynchrone bewerkingen in behandeling zijn. Als u daarentegen probeert aan te roepen Method1Async(string param)
voordat een eerdere aanroep is voltooid, wordt met de methode een InvalidOperationException.
Met userState
de parameter voor de overbelasting van meerdere aanroepen kunt u onderscheid maken tussen asynchrone bewerkingen. U geeft een unieke waarde op (bijvoorbeeld een GUID- of hashcode) voor elke aanroep naar Method1Async(string param, object userState)
, en wanneer elke bewerking is voltooid, kan uw gebeurtenis-handler bepalen welk exemplaar van de bewerking de voltooiingsgebeurtenis heeft gegenereerd.
Bijhouden van bewerkingen die in behandeling zijn
Als u de overbelasting met meerdere aanroepen gebruikt, moet uw code de userState
objecten (taak-id's) bijhouden voor taken die in behandeling zijn. Voor elke aanroep naar Method1Async(string param, object userState)
, genereert u doorgaans een nieuw, uniek userState
object en voegt u dit toe aan een verzameling. Wanneer de taak die overeenkomt met dit userState
object de voltooiingsbeurtenis genereert, wordt de implementatie van de voltooiingsmethode onderzocht AsyncCompletedEventArgs.UserState en verwijderd uit uw verzameling. Op deze manier gebruikt de userState
parameter de rol van een taak-id.
Notitie
U moet voorzichtig zijn met het opgeven van een unieke waarde voor userState
uw aanroepen naar overbelastingen met meerdere aanroepen. Niet-unieke taak-id's veroorzaken de asynchrone klasse een ArgumentException.
Bewerkingen die in behandeling zijn annuleren
Het is belangrijk dat u asynchrone bewerkingen op elk gewenst moment kunt annuleren voordat deze zijn voltooid. Klassen die het Asynchrone patroon op basis van gebeurtenissen implementeren, hebben een CancelAsync
methode (als er slechts één asynchrone methode is) of een MethodNameAsyncCancel-methode (als er meerdere asynchrone methoden zijn).
Methoden die meerdere aanroepen toestaan, nemen een userState
parameter, die kan worden gebruikt om de levensduur van elke taak bij te houden. CancelAsync
neemt een userState
parameter, waarmee u bepaalde taken die in behandeling zijn, kunt annuleren.
Methoden die slechts één bewerking tegelijk in behandeling ondersteunen, zoals Method1Async(string param)
, kunnen niet worden geannuleerd.
Voortgangsupdates en incrementele resultaten ontvangen
Een klasse die voldoet aan het Asynchrone patroon op basis van gebeurtenissen, kan eventueel een gebeurtenis bieden voor het bijhouden van de voortgang en incrementele resultaten. Dit wordt doorgaans benoemd ProgressChanged
of MethodNameProgressChanged en de bijbehorende gebeurtenis-handler neemt een ProgressChangedEventArgs parameter.
De gebeurtenis-handler voor de ProgressChanged
gebeurtenis kan de ProgressChangedEventArgs.ProgressPercentage eigenschap onderzoeken om te bepalen welk percentage van een asynchrone taak is voltooid. Deze eigenschap varieert van 0 tot 100 en kan worden gebruikt om de Value eigenschap van een ProgressBar. Als er meerdere asynchrone bewerkingen in behandeling zijn, kunt u de ProgressChangedEventArgs.UserState eigenschap gebruiken om te onderscheiden welke bewerking de voortgang rapporteert.
Sommige klassen kunnen incrementele resultaten rapporteren wanneer asynchrone bewerkingen worden uitgevoerd. Deze resultaten worden opgeslagen in een klasse die is afgeleid van ProgressChangedEventArgs en ze worden weergegeven als eigenschappen in de afgeleide klasse. U hebt toegang tot deze resultaten in de gebeurtenis-handler voor de ProgressChanged
gebeurtenis, net zoals u toegang hebt tot de ProgressPercentage eigenschap. Als er meerdere asynchrone bewerkingen in behandeling zijn, kunt u de UserState eigenschap gebruiken om te onderscheiden welke bewerking incrementele resultaten rapporteert.
Zie ook
- ProgressChangedEventArgs
- BackgroundWorker
- AsyncCompletedEventArgs
- Procedure: Onderdelen gebruiken die ondersteuning bieden voor het Asynchrone patroon op basis van gebeurtenissen
- Procedure: Een bewerking uitvoeren op de achtergrond
- Procedure: Een formulier implementeren dat gebruikmaakt van een achtergrondbewerking
- Asynchroon patroon (EAP) op basis van gebeurtenissen
- Aanbevolen procedures voor het implementeren van het Asynchrone patroon op basis van gebeurtenissen
- Bepalen wanneer het Asynchrone patroon op basis van gebeurtenissen moet worden geïmplementeerd