Share via


SyncAsyncEventHandler<T> Delegar

Definição

Representa um método que pode manipular um evento e executar de forma síncrona ou assíncrona.

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 dos argumentos de evento que derivam ou são iguais a SyncAsyncEventArgs.

Parâmetros

e
T

Uma SyncAsyncEventArgs instância que contém os dados do evento.

Valor Retornado

Uma tarefa que representa o manipulador. Você pode retornar CompletedTask se estiver implementando um manipulador de sincronização. Consulte a seção Comentários para obter mais detalhes.

Exemplos

Se você estiver usando os métodos de bloqueio síncronos de um cliente (ou seja, métodos sem um sufixo Assíncrono), eles gerarão eventos que exigem que os manipuladores também sejam executados de forma síncrona. Embora a assinatura do manipulador retorne um , você deve escrever um Taskcódigo de sincronização regular que bloqueia e retorna CompletedTask quando concluído.

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
tratamento de exceções na Biblioteca Paralela de Tarefas para evitar exceções sem tratamento que desmarcam seu processo. Se você precisar absolutamente do método assíncrono para executar antes de retornar do manipulador, poderá chamar myAsyncTask.GetAwaiter().GetResult(). Lembre-se de que isso pode causar a fome do ThreadPool. Consulte a observação sync-over-async nos Comentários para obter mais detalhes.

Se você estiver usando os métodos assíncronos e sem bloqueio de um cliente (ou seja, métodos com um sufixo Assíncrono), eles gerarão eventos que esperam que os manipuladores sejam executados de forma assíncrona.

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

await client.SnoozeAsync();

O mesmo evento pode ser gerado de caminhos de código síncronos e assíncronos, dependendo se você está chamando métodos de sincronização ou assíncronos em um cliente. Se você escrever um manipulador assíncrono, mas elevá-lo de um método de sincronização, o manipulador fará a sincronização sobre assíncrona e poderá causar a fome do ThreadPool. Consulte a observação em Comentários para obter mais detalhes. Você deve usar a IsRunningSynchronously propriedade para marcar como o evento está sendo gerado e implementar seu manipulador adequadamente. Aqui está um manipulador de exemplo seguro para invocar de caminhos de código assíncrono e de sincronização.

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

Comentários

A maioria das bibliotecas de clientes do Azure para .NET oferece métodos síncronos e assíncronos para chamar serviços do Azure. Você pode distinguir os métodos assíncronos pelo sufixo Assíncrono. Por exemplo, BlobClient.Download e BlobClient.DownloadAsync fazem a mesma chamada REST subjacente e diferem apenas se eles bloqueiam. É recomendável usar nossos métodos assíncronos para novos aplicativos, mas também há casos perfeitamente válidos para usar métodos de sincronização. Essas semânticas de invocação de método duplo permitem flexibilidade, mas exigem um pouco de cuidado extra ao escrever manipuladores de eventos.

O SyncAsyncEventHandler é um delegado usado por eventos em bibliotecas de clientes do Azure para representar um manipulador de eventos que pode ser invocado de caminhos de código assíncronos ou de sincronização. Ele usa argumentos de evento derivados que SyncAsyncEventArgs contêm informações importantes para escrever seu manipulador de eventos:

  • CancellationToken é um token de cancelamento relacionado à operação original que gerou o evento. É importante que o manipulador passe esse token para qualquer operação síncrona assíncrona ou de execução longa que use um token para que o cancelamento (por meio de algo como new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token, por exemplo) seja propagado corretamente.
  • IsRunningSynchronously é um sinalizador que indica se o manipulador foi invocado de forma síncrona ou assíncrona. Se você estiver chamando métodos de sincronização em seu cliente, deverá usar métodos de sincronização para implementar o manipulador de eventos (você pode retornar CompletedTask). Se você estiver chamando métodos assíncronos em seu cliente, deverá usar métodos assíncronos sempre que possível para implementar o manipulador de eventos. Se você não estiver no controle de como o cliente será usado ou quiser escrever um código mais seguro, deverá marcar a IsRunningSynchronously propriedade e chamar métodos de sincronização ou assíncronos conforme indicado.
  • A maioria dos eventos personalizará os dados do evento derivando de SyncAsyncEventArgs e incluindo detalhes sobre o que disparou o evento ou fornecendo opções para reagir. Muitas vezes, isso incluirá uma referência ao cliente que gerou o evento caso você precise dele para processamento adicional.

Quando um evento que usa SyncAsyncEventHandler é acionado, os manipuladores serão executados sequencialmente para evitar a introdução de qualquer paralelismo não intencional. Os manipuladores de eventos serão concluídos antes de retornar o controle para o caminho do código que aciona o evento. Isso significa bloquear eventos gerados de forma síncrona e aguardar a conclusão do retornado Task para eventos gerados de forma assíncrona.

Todas as exceções geradas de um manipulador serão encapsuladas em um único AggregateException. Se um manipulador gerar uma exceção, ele não impedirá que outros manipuladores sejam executados. Isso também é relevante para cancelamento porque todos os manipuladores ainda serão gerados se ocorrer cancelamento. Você deve passar CancellationToken para operações síncronas assíncronas ou de longa execução e considerar chamar ThrowIfCancellationRequested() em manipuladores pesados de computação.

Um intervalo de rastreamento distribuído é encapsulado em torno de seus manipuladores usando o nome do evento para que você possa ver quanto tempo seus manipuladores levaram para serem executados, se eles fizeram outras chamadas para os serviços do Azure e detalhes sobre quaisquer exceções que foram geradas.

A execução de código assíncrono de um caminho de código de sincronização geralmente é conhecida como sync-over-async porque você está recebendo o comportamento de sincronização, mas ainda invocando todos os computadores assíncronos. Consulte Diagnosing.NET Core ThreadPool Starvation with PerfView para obter uma explicação detalhada de como isso pode causar sérios problemas de desempenho. Recomendamos que você use o IsRunningSynchronously sinalizador para evitar a fome do ThreadPool.

Aplica-se a