Partager via


SyncAsyncEventHandler<T> Délégué

Définition

Représente une méthode qui peut gérer un événement et s’exécuter de manière synchrone ou asynchrone.

public delegate System.Threading.Tasks.Task SyncAsyncEventHandler<T>(T e) where T : SyncAsyncEventArgs;
type SyncAsyncEventHandler<'T (requires 'T :> SyncAsyncEventArgs)> = delegate of 'T -> Task
Public Delegate Function SyncAsyncEventHandler(Of T)(e As T) As Task 

Paramètres de type

T

Type des arguments d’événement dérivant ou égal à SyncAsyncEventArgs.

Paramètres

e
T

Une SyncAsyncEventArgs instance qui contient les données d’événement.

Valeur renvoyée

Tâche qui représente le gestionnaire. Vous pouvez retourner CompletedTask si vous implémentez un gestionnaire de synchronisation. Pour plus d’informations, consultez la section Remarques.

Exemples

Si vous utilisez les méthodes synchrones bloquantes d’un client (c’est-à-dire, les méthodes sans suffixe Async), elles déclenchent également des événements qui nécessitent que les gestionnaires s’exécutent de manière synchrone. Même si la signature de votre gestionnaire retourne un , vous devez écrire du Taskcode de synchronisation standard qui bloque et retourne CompletedTask lorsque vous avez terminé.

var client = new AlarmClient();
client.Ring += (SyncAsyncEventArgs e) =>
{
    Console.WriteLine("Wake up!");
    return Task.CompletedTask;
};

client.Snooze();
   If you need to call an async method from a synchronous event handler,
   you have two options.  You can use <xref data-throw-if-not-resolved="true" uid="System.Threading.Tasks.Task.Run(System.Action)"></xref> to
   queue a task for execution on the ThreadPool without waiting on it to
   complete.  This "fire and forget" approach may not run before your
   handler finishes executing.  Be sure to understand
gestion des exceptions dans la bibliothèque parallèle de tâches pour éviter que les exceptions non gérées détruisent votre processus. Si vous avez absolument besoin de l’exécution de la méthode asynchrone avant de retourner à partir de votre gestionnaire, vous pouvez appeler myAsyncTask.GetAwaiter().GetResult(). N’oubliez pas que cela peut provoquer une famine de ThreadPool. Pour plus d’informations, consultez la note sync-over-async dans Remarques.

Si vous utilisez les méthodes asynchrones et non bloquantes d’un client (c’est-à-dire les méthodes avec un suffixe Async), elles déclenchent des événements qui s’attendent à ce que les gestionnaires s’exécutent de manière asynchrone.

var client = new AlarmClient();
client.Ring += async (SyncAsyncEventArgs e) =>
{
    await Console.Out.WriteLineAsync("Wake up!");
};

await client.SnoozeAsync();

Le même événement peut être déclenché à partir des chemins de code synchrones et asynchrones, selon que vous appelez des méthodes de synchronisation ou asynchrones sur un client. Si vous écrivez un gestionnaire asynchrone, mais que vous le déclenchez à partir d’une méthode de synchronisation, le gestionnaire effectue la synchronisation sur async et peut provoquer une insuffisance de ThreadPool. Pour plus d’informations, consultez la note dans Remarques. Vous devez utiliser la IsRunningSynchronously propriété pour case activée comment l’événement est déclenché et implémenter votre gestionnaire en conséquence. Voici un exemple de gestionnaire qui peut être appelé en toute sécurité à partir des chemins de code de synchronisation et de code asynchrone.

var client = new AlarmClient();
client.Ring += async (SyncAsyncEventArgs e) =>
{
    if (e.IsRunningSynchronously)
    {
        Console.WriteLine("Wake up!");
    }
    else
    {
        await Console.Out.WriteLineAsync("Wake up!");
    }
};

client.Snooze(); // sync call that blocks
await client.SnoozeAsync(); // async call that doesn't block

Remarques

La plupart des bibliothèques clientes Azure pour .NET offrent des méthodes synchrones et asynchrones pour appeler des services Azure. Vous pouvez distinguer les méthodes asynchrones par leur suffixe Async. Par exemple, BlobClient.Download et BlobClient.DownloadAsync effectuent le même appel REST sous-jacent et diffèrent uniquement par leur blocage. Nous vous recommandons d’utiliser nos méthodes asynchrones pour les nouvelles applications, mais il existe également des cas parfaitement valides pour l’utilisation de méthodes de synchronisation. Ces sémantiques d’appel de méthode double permettent la flexibilité, mais nécessitent un peu de soin lors de l’écriture de gestionnaires d’événements.

SyncAsyncEventHandler est un délégué utilisé par les événements dans les bibliothèques clientes Azure pour représenter un gestionnaire d’événements qui peut être appelé à partir de chemins de code de synchronisation ou asynchrones. Il prend des arguments d’événement dérivant de SyncAsyncEventArgs qui contiennent des informations importantes pour l’écriture de votre gestionnaire d’événements :

  • CancellationToken est un jeton d’annulation lié à l’opération d’origine qui a déclenché l’événement. Il est important que votre gestionnaire transmette ce jeton à toutes les opérations synchrones asynchrones ou de longue durée qui prennent un jeton afin que l’annulation (par new CancellationTokenSource(TimeSpan.FromSeconds(10)).Tokenexemple, par exemple) se propage correctement.
  • IsRunningSynchronously est un indicateur indiquant si votre gestionnaire a été appelé de manière synchrone ou asynchrone. Si vous appelez des méthodes de synchronisation sur votre client, vous devez utiliser des méthodes de synchronisation pour implémenter votre gestionnaire d’événements (vous pouvez retourner CompletedTask). Si vous appelez des méthodes asynchrones sur votre client, vous devez utiliser des méthodes asynchrones si possible pour implémenter votre gestionnaire d’événements. Si vous ne contrôlez pas la façon dont le client sera utilisé ou si vous souhaitez écrire du code plus sûr, vous devez case activée la propriété et appeler des IsRunningSynchronously méthodes de synchronisation ou asynchrones comme indiqué.
  • La plupart des événements personnalisent les données d’événement en dérivant de SyncAsyncEventArgs et en incluant des détails sur ce qui a déclenché l’événement ou en fournissant des options de réaction. Souvent, cela inclut une référence au client qui a déclenché l’événement au cas où vous en aviez besoin pour un traitement supplémentaire.

Lorsqu’un événement utilisant SyncAsyncEventHandler est déclenché, les gestionnaires sont exécutés séquentiellement pour éviter d’introduire un parallélisme involontaire. Les gestionnaires d’événements se terminent avant de renvoyer le contrôle au chemin de code qui déclenche l’événement. Cela signifie le blocage des événements déclenchés de manière synchrone et l’attente de la fin du retour Task pour les événements déclenchés de manière asynchrone.

Toutes les exceptions levées à partir d’un gestionnaire seront encapsulées dans un seul AggregateException. Si un gestionnaire lève une exception, cela n’empêchera pas d’autres gestionnaires de s’exécuter. Cela est également pertinent pour l’annulation, car tous les gestionnaires sont toujours déclenchés si l’annulation se produit. Vous devez passer à des opérations synchrones asynchrones CancellationToken ou de longue durée et envisager d’appeler ThrowIfCancellationRequested() des gestionnaires de calcul lourds.

Une étendue de suivi distribuée est encapsulée autour de vos gestionnaires à l’aide du nom de l’événement afin que vous puissiez voir la durée d’exécution de vos gestionnaires, s’ils ont effectué d’autres appels aux services Azure et des détails sur les exceptions levées.

L’exécution de code asynchrone à partir d’un chemin de code de synchronisation est généralement appelée synchronisation-sur-async, car vous obtenez un comportement de synchronisation, mais vous appelez tout le système asynchrone. Pour obtenir une explication détaillée de la façon dont cela peut entraîner de graves problèmes de performances , consultez Diagnosing.NET Principal ThreadPool Starvation avec PerfView . Nous vous recommandons d’utiliser l’indicateur pour éviter la IsRunningSynchronously famine de ThreadPool.

S’applique à