Share via


SyncAsyncEventHandler<T> Delegado

Definición

Representa un método que puede controlar un evento y ejecutar de forma sincrónica o asincrónica.

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 

Parámetros de tipo

T

Tipo de los argumentos de evento que derivan o son iguales a SyncAsyncEventArgs.

Parámetros

e
T

Instancia SyncAsyncEventArgs de que contiene los datos del evento.

Valor devuelto

Tarea que representa el controlador. Puede devolver CompletedTask si implementa un controlador de sincronización. Consulte la sección Comentarios para obtener más detalles.

Ejemplos

Si usa los métodos de bloqueo sincrónicos de un cliente (es decir, los métodos sin un sufijo asincrónico), generarán eventos que requieran que los controladores también se ejecuten de forma sincrónica. Aunque la firma del controlador devuelva un Task, debe escribir código de sincronización normal que bloquee y devuelva CompletedTask cuando haya terminado.

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
Control de excepciones en la biblioteca paralela de tareas para evitar excepciones no controladas anulando el proceso. Si necesita absolutamente el método asincrónico para ejecutarse antes de volver desde el controlador, puede llamar a myAsyncTask.GetAwaiter().GetResult(). Tenga en cuenta que esto puede provocar el hambre de ThreadPool. Consulte la nota sync-over-async en Comentarios para obtener más detalles.

Si usa los métodos asincrónicos y sin bloqueo de un cliente (es decir, los métodos con un sufijo asincrónico), generarán eventos que esperan que los controladores se ejecuten de forma asincrónica.

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

await client.SnoozeAsync();

El mismo evento se puede generar desde rutas de acceso de código sincrónicas y asincrónicas en función de si llama a métodos sincrónicos o asincrónicos en un cliente. Si escribe un controlador asincrónico pero lo genera desde un método de sincronización, el controlador realizará la sincronización a través de async y puede provocar el colapso de ThreadPool. Consulte la nota en Comentarios para obtener más detalles. Debe usar la IsRunningSynchronously propiedad para comprobar cómo se genera el evento e implementar el controlador en consecuencia. Este es un controlador de ejemplo que es seguro invocar desde rutas de acceso de código sincronizadas y asincrónicas.

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

Comentarios

La mayoría de las bibliotecas cliente de Azure para .NET ofrecen métodos sincrónicos y asincrónicos para llamar a servicios de Azure. Puede distinguir los métodos asincrónicos por su sufijo asincrónico. Por ejemplo, BlobClient.Download y BlobClient.DownloadAsync realizan la misma llamada REST subyacente y solo difieren en si bloquean. Se recomienda usar nuestros métodos asincrónicos para nuevas aplicaciones, pero también hay casos perfectamente válidos para usar métodos de sincronización. Esta semántica de invocación de método dual permite flexibilidad, pero requiere un poco más de cuidado al escribir controladores de eventos.

SyncAsyncEventHandler es un delegado que usan los eventos de las bibliotecas cliente de Azure para representar un controlador de eventos que se puede invocar desde rutas de acceso de código sincronizadas o asincrónicas. Toma argumentos de evento derivados de SyncAsyncEventArgs que contienen información importante para escribir el controlador de eventos:

  • CancellationToken es un token de cancelación relacionado con la operación original que generó el evento. Es importante que el controlador pase este token a cualquier operación sincrónica asincrónica o de larga duración que tome un token para que la cancelación (a través de algo como new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token, por ejemplo) se propague correctamente.
  • IsRunningSynchronously es una marca que indica si el controlador se invocó de forma sincrónica o asincrónica. Si llama a métodos de sincronización en el cliente, debe usar métodos de sincronización para implementar el controlador de eventos (puede devolver CompletedTask). Si llama a métodos asincrónicos en el cliente, debe usar métodos asincrónicos siempre que sea posible para implementar el controlador de eventos. Si no está en control de cómo se usará el cliente o desea escribir código más seguro, debe comprobar la IsRunningSynchronously propiedad y llamar a los métodos sincronizados o asincrónicos según se indique.
  • La mayoría de los eventos personalizarán los datos de eventos derivando de SyncAsyncEventArgs e incluyendo detalles sobre lo que desencadenó el evento o proporcionar opciones para reaccionar. Muchas veces esto incluirá una referencia al cliente que generó el evento en caso de que lo necesite para un procesamiento adicional.

Cuando se genera un evento mediante SyncAsyncEventHandler, los controladores se ejecutarán secuencialmente para evitar introducir cualquier paralelismo no deseado. Los controladores de eventos finalizarán antes de devolver el control a la ruta de acceso del código que genera el evento. Esto significa bloquear los eventos generados de forma sincrónica y esperar a que se complete el devuelto Task para los eventos generados de forma asincrónica.

Todas las excepciones producidas desde un controlador se encapsularán en un único AggregateException. Si un controlador produce una excepción, no impedirá que se ejecuten otros controladores. Esto también es relevante para la cancelación porque todos los controladores todavía se generan si se produce la cancelación. Debe pasar CancellationToken a operaciones sincrónicas asincrónicas o de larga duración y considerar la posibilidad de llamar ThrowIfCancellationRequested() a en controladores de proceso pesados.

Un intervalo de seguimiento distribuido se ajusta alrededor de los controladores mediante el nombre del evento para que pueda ver cuánto tiempo tardaron los controladores en ejecutarse, si realizaron otras llamadas a servicios de Azure y detalles sobre las excepciones que se produjeron.

La ejecución de código asincrónico desde una ruta de acceso de código de sincronización se conoce normalmente como sincronización a través de async porque se obtiene el comportamiento de sincronización, pero sigue invocando toda la maquinaria asincrónica. Consulte Diagnosing.NET Core ThreadPool Starvation with PerfView para obtener una explicación detallada de cómo puede causar problemas graves de rendimiento. Se recomienda usar la IsRunningSynchronously marca para evitar el hambre de ThreadPool.

Se aplica a