Como e quando usar 'async' e 'aguardar'

Do meu entendimento, uma das principais coisas que async e await do is to make code easy to write and read-but is using them equal to spawning background threads to perform long duration logic?

Estou a tentar o exemplo mais básico. Adicionei alguns comentários na linha. Pode esclarecer-me?

// I don't understand why this method must be marked as `async`.
private async void button1_Click(object sender, EventArgs e)
{
    Task<int> access = DoSomethingAsync();
    // task independent stuff here

    // this line is reached after the 5 seconds sleep from 
    // DoSomethingAsync() method. Shouldn't it be reached immediately? 
    int a = 1; 

    // from my understanding the waiting should be done here.
    int x = await access; 
}

async Task<int> DoSomethingAsync()
{
    // is this executed on a background thread?
    System.Threading.Thread.Sleep(5000);
    return 1;
}
Author: Roy, 2013-01-22

20 answers

Ao usar async e await o compilador gera uma máquina de estado em segundo plano.

Aqui está um exemplo sobre o qual espero poder explicar alguns dos detalhes de alto nível que estão acontecendo:
public async Task MyMethodAsync()
{
    Task<int> longRunningTask = LongRunningOperationAsync();
    // independent work which doesn't need the result of LongRunningOperationAsync can be done here

    //and now we call await on the task 
    int result = await longRunningTask;
    //use the result 
    Console.WriteLine(result);
}

public async Task<int> LongRunningOperationAsync() // assume we return an int from this long running operation 
{
    await Task.Delay(1000); // 1 second delay
    return 1;
}
Então, o que acontece aqui?
  1. Task<int> longRunningTask = LongRunningOperationAsync(); inicia a execução LongRunningOperation

  2. O trabalho independente é feito em vamos assumir que o fio principal (Thread ID = 1) então await longRunningTask é alcançado.

    Agora, se o longRunningTask ainda não terminou e ainda está em execução, MyMethodAsync() irá voltar ao seu método de chamada, assim a linha principal não fica bloqueada. Quando o longRunningTask é feito então um thread do ThreadPool (pode ser qualquer thread) retornará a MyMethodAsync() em seu contexto anterior e continuará a execução (neste caso imprimindo o resultado para a consola).

Um segundo caso seria que o longRunningTask já terminou a sua execução e o resultado está disponível. Ao chegar ao await longRunningTask já temos o resultado para que o código continue a executar na mesma linha. (neste caso, imprimir o resultado para consola). Claro que este não é o caso para o exemplo acima, onde há um Task.Delay(1000) envolvido.

 573
Author: Dan Dinu, 2017-10-11 23:43:35

Mais para as outras respostas, dê uma olhada Espere (C# Referência)

E mais especificamente no exemplo incluído, explica um pouco a sua situação

O seguinte exemplo de formulários do Windows ilustra o uso de aguardar num método async, esperar Assíncronoasync. Contraste o comportamento disso método com o comportamento de WaitSynchronously. Sem esperar o operador aplicado a uma tarefa, corre de forma síncrona apesar do uso do modificador async na sua definição e uma chamada para Segmento.Dorme no seu corpo.

private async void button1_Click(object sender, EventArgs e)
{
    // Call the method that runs asynchronously.
    string result = await WaitAsynchronouslyAsync();

    // Call the method that runs synchronously.
    //string result = await WaitSynchronously ();

    // Display the result.
    textBox1.Text += result;
}

// The following method runs asynchronously. The UI thread is not
// blocked during the delay. You can move or resize the Form1 window 
// while Task.Delay is running.
public async Task<string> WaitAsynchronouslyAsync()
{
    await Task.Delay(10000);
    return "Finished";
}

// The following method runs synchronously, despite the use of async.
// You cannot move or resize the Form1 window while Thread.Sleep
// is running because the UI thread is blocked.
public async Task<string> WaitSynchronously()
{
    // Add a using directive for System.Threading.
    Thread.Sleep(10000);
    return "Finished";
}
 133
Author: Adriaan Stander, 2017-05-23 09:31:58
Pelo que sei, uma das principais coisas que async e as esperam fazer é tornar o código fácil de escrever e ler.
Eles devem tornar o código assíncrono fácil de escrever e ler, sim.
É a mesma coisa que criar fios de fundo para executar a lógica de longa duração?
De todo.

/ / Eu não entendo por que este método deve ser marcado como "async".

A palavra-chave async activa a await palavra-chave. Assim, qualquer método que utilize await deve ser marcado async.

/ / Esta linha é atingida após os 5 segundos de latência do método Dosometingasync (). Não deveria ser alcançado imediatamente?

Não, porque os métodos async não são executados noutro tópico por omissão.

/ / isto é executado num tópico de fundo?

Não.

Podes encontrar a minha async/await Intro útil. Os documentosoficiais MSDN são também invulgarmente bom (particularmente a secção da torneira), e a equipa {[[0]} fez uma excelente FAQ .

 110
Author: Stephen Cleary, 2014-06-13 12:49:02

Explicação

Aqui está um exemplo rápido de async/wait a um alto nível. Há muito mais detalhes a considerar além disso.

Nota: Task.Delay(1000) simula trabalhar durante 1 segundo. Acho que é melhor pensar nisto como esperar por uma resposta de um recurso externo. Uma vez que o nosso código está à espera de uma resposta, o sistema pode configurar a tarefa de execução para o lado e voltar a ele assim que estiver terminado. Entretanto, pode fazer outro trabalho sobre isso. segmento.

No exemplo abaixo, o primeiro bloco está a fazer exactamente isso. Ele inicia todas as tarefas imediatamente (as linhas Task.Delay) e os coloca de lado. O código irá parar na linha await a até que o atraso de 1 segundo seja feito antes de ir para a próxima linha. Desde b, c, d, e e todos começaram a executar quase ao mesmo tempo que a (devido à falta da espera), eles devem terminar aproximadamente ao mesmo tempo neste caso.

No exemplo abaixo, o segundo bloco está começando uma tarefa e esperando que ela termine (isso é o que await faz) antes de iniciar as tarefas subsequentes. Cada iteração disto leva um segundo. O await está a parar o programa e à espera do resultado antes de continuar. Esta é a principal diferença entre o primeiro e o segundo blocos.

Exemplo

Console.WriteLine(DateTime.Now);

// This block takes 1 second to run because all
// 5 tasks are running simultaneously
{
    var a = Task.Delay(1000);
    var b = Task.Delay(1000);
    var c = Task.Delay(1000);
    var d = Task.Delay(1000);
    var e = Task.Delay(1000);

    await a;
    await b;
    await c;
    await d;
    await e;
}

Console.WriteLine(DateTime.Now);

// This block takes 5 seconds to run because each "await"
// pauses the program until the task finishes
{
    await Task.Delay(1000);
    await Task.Delay(1000);
    await Task.Delay(1000);
    await Task.Delay(1000);
    await Task.Delay(1000);
}
Console.WriteLine(DateTime.Now);

Resultado:

5/24/2017 2:22:50 PM
5/24/2017 2:22:51 PM (First block took 1 second)
5/24/2017 2:22:56 PM (Second block took 5 seconds)

Informação Extra sobre o Sincronizationcontext

Nota: é aqui que as coisas ficam um pouco enevoado para mim, por isso se eu estiver errado em alguma coisa, por favor corrija-me e eu actualizarei a resposta. É importante ter uma compreensão básica de como isso funciona, mas você pode sobreviver sem ser um especialista nisso, desde que você nunca use ConfigureAwait(false), Embora você provavelmente vai perder alguma oportunidade de otimização, eu presumo. Há um aspecto disto que torna o conceito async/wait um pouco mais complicado de entender. Este é o fato de que neste exemplo, tudo isso está acontecendo no mesmo thread (ou pelo menos o que parece ser o mesmo thread em relação ao seu Sincronizationcontext). Por padrão, await irá restaurar o contexto de sincronização do tópico original em que estava a correr. Por exemplo, em ASP.NET você tem um HttpContext que é amarrado a um thread quando um pedido entra. Este contexto contém coisas específicas para o pedido Http original, como o objeto de pedido original que tem coisas como linguagem, endereço IP, cabeçalhos, etc. Se mudar de tópico a meio do processamento de algo, você poderia potencialmente acabar tentando tirar informações deste objeto em um outro HttpContext que poderia ser desastroso. Se você sabe que não estará usando o contexto para nada, você pode optar por "não se importar" com isso. Isto basicamente permite que seu código seja executado em um tópico separado sem trazer o contexto ao redor com ele. Como consegues isso? Por padrão, o código await a; realmente está fazendo uma suposição de que você quer capturar e repor o contexto:
await a; //Same as the line below
await a.ConfigureAwait(true);

Se quiser permitir que o código principal continue num novo tópico sem o contexto original, basta usar o false em vez do true para que ele saiba que não precisa de restaurar o contexto.

await a.ConfigureAwait(false);

Depois de o programa ser feito em pausa, ele irá continuar potencialmente num tópico completamente diferente com um contexto diferente. Isto é de onde a melhoria de desempenho viria -- ele poderia continuar em qualquer tópico disponível sem ter que restaurar o contexto original com o qual ele começou.

Isto é confuso? Claro que sim! Consegues descobrir? Provavelmente! Uma vez que você tem uma compreensão dos conceitos, em seguida, avançar para as explicações de Stephen Cleary que tendem a ser orientados mais para alguém com uma compreensão técnica de async/esperar já.
 95
Author: Joe Phillips, 2018-05-08 14:58:30

Mostrando as explicações acima em acção num simples programa de consola -

class Program
{
    static void Main(string[] args)
    {
        TestAsyncAwaitMethods();
        Console.WriteLine("Press any key to exit...");
        Console.ReadLine();
    }

    public async static void TestAsyncAwaitMethods()
    {
        await LongRunningMethod();
    }

    public static async Task<int> LongRunningMethod()
    {
        Console.WriteLine("Starting Long Running method...");
        await Task.Delay(5000);
        Console.WriteLine("End Long Running method...");
        return 1;
    }
}

E a saída é:

Starting Long Running method...
Press any key to exit...
End Long Running method...

Assim,

  1. O Main inicia o método de longa duração através do método Testasyncawaitmetods. Que retorna imediatamente sem parar o tópico atual e vemos imediatamente 'pressione qualquer tecla para sair' mensagem
  2. todo este tempo, o LongRunningMethod está a correr em segundo plano. Uma vez concluído, outro tópico de Threadpool pega neste contexto e mostra a mensagem final

Assim, o fio não está bloqueado.

 45
Author: sppc42, 2015-08-13 09:32:13
Acho que escolheste um mau exemplo com System.Threading.Thread.Sleep

O Ponto de uma tarefa async é deixá - la executar em segundo plano sem bloquear o tópico principal, como por exemplo fazer um DownloadFileAsync

System.Threading.Thread.Sleep não é algo que está "sendo feito", apenas dorme, e, portanto, sua próxima linha é alcançada após 5 segundos ...

Ler este artigo, eu acho que é uma grande explicação de async e await conceito: http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx

 35
Author: Vnuk, 2016-01-29 07:40:48
Aqui está um programa de consola rápida para deixar claro para aqueles que o seguem. O método "TaskToDo" é o seu método de longa duração que você quer fazer async. Fazê-lo correr Async é feito pelo método TestAsync. O método de loops de teste é executado através das tarefas "Tashtodo" e executa-os Async. Você pode ver isso nos resultados porque eles não completam na mesma ordem de execução a execução - eles estão relatando para o fio UI console quando eles terminam. Simplista, mas acho que o simplista exemplos mostram melhor o núcleo do padrão do que mais exemplos envolvidos:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace TestingAsync
{
    class Program
    {
        static void Main(string[] args)
        {
            TestLoops();
            Console.Read();
        }

        private static async void TestLoops()
        {
            for (int i = 0; i < 100; i++)
            {
                await TestAsync(i);
            }
        }

        private static Task TestAsync(int i)
        {
            return Task.Run(() => TaskToDo(i));
        }

        private async static void TaskToDo(int i)
        {
            await Task.Delay(10);
            Console.WriteLine(i);
        }
    }
}
 17
Author: MarkWalls, 2015-09-11 09:23:45
([1]) esta resposta tem por objectivo fornecer algumas informações específicas sobre: ASP.NET.

Utilizando async / wait no controlador MVC, é possível aumentar a utilização do conjunto de linhas e obter um rendimento muito melhor, como explicado no artigo abaixo,

Http://www.asp.net/mvc/tutorials/mvc-4/using-asynchronous-methods-in-aspnet-mvc-4

Em aplicações web que vêem um grande número de pedidos simultâneos em arranque ou com uma carga pesada (em que a concorrência aumento súbito), fazer estas chamadas de serviço web assíncronas irá aumentar o capacidade de Resposta da sua aplicação. Um pedido assíncrono a mesma quantidade de tempo para processar como um pedido síncrono. Por exemplo, se um pedido faz uma chamada de serviço web que requer dois segundos para completo, o pedido leva dois segundos se é realizado síncrono ou assíncrono. No entanto, durante uma chamada assíncrona, um tópico não está bloqueado de responder a outros pedidos enquanto espera que o primeiro pedido seja completado. Portanto, assíncrono os pedidos impedem o crescimento da fila de Pedidos e do conjunto de linhas quando existem muitos pedidos concorrentes que invocam operações de longa duração.

 10
Author: Lex Li, 2014-09-08 02:06:42

Para ser honesto, ainda acho que a melhor explicação é aquela sobre o futuro e as promessas na Wikipedia: http://en.wikipedia.org/wiki/Futures_and_promises

A ideia básica é que você tem um conjunto separado de tópicos que executam tarefas assíncronamente. Ao usá-lo. O objeto, no entanto, faz a promessa de que irá executar a operação em algum momento e dar-lhe o resultado quando você solicitá-lo. Isto significa que irá bloquear quando você solicitar o resultado e não tem terminado, mas execute no grupo de linhas caso contrário.

A partir daí você pode otimizar as coisas: algumas operações podem ser implementadas async e você pode otimizar coisas como arquivo IO e comunicação de rede, batendo juntos pedidos subsequentes e/ou reordenando-os. Eu não tenho certeza se isso já está no quadro de tarefas da Microsoft - mas se não for isso seria uma das primeiras coisas que eu acrescentaria.

Você pode realmente implementar o tipo de padrão futuro - com rendimentos em C # 4.0. Se você quer saber como funciona exatamente, eu posso recomendar este link que faz um trabalho decente: http://code.google.com/p/fracture/source/browse/trunk/Squared/TaskLib / . No entanto, se você começar a brincar com ele, você vai notar que você realmente precisa de suporte de linguagem se você quiser fazer todas as coisas legais -- que é exatamente o que a Microsoft fez.

 9
Author: atlaste, 2013-01-22 10:16:25

Todas as respostas aqui usam a tarefa.Delay() ou alguma outra função construída em async. Mas aqui está meu exemplo que não usa nenhuma dessas funções async:

    // Starts counting to a large numbewr and then immediately displays message "i'm counting...". 
    // Then it waits for task to finish and displays "finished, press any key".
    static void asyncTest ()
    {
        Console.WriteLine("Started asyncTest()");
        Task<long> task = asyncTest_count();
        Console.WriteLine("Started counting, please wait...");
        task.Wait(); // if you comment this line you will see that message "Finished counting" will be displayed before we actually finished counting.
        //Console.WriteLine("Finished counting to " + task.Result.ToString()); // using task.Result seems to also call task.Wait().
        Console.WriteLine("Finished counting.");
        Console.WriteLine("Press any key to exit program.");
        Console.ReadLine();
    }

    static async Task<long> asyncTest_count()
    {
        long k = 0;
        Console.WriteLine("Started asyncTest_count()");
        await Task.Run(() =>
        {
            long countTo = 100000000;
            int prevPercentDone = -1;
            for (long i = 0; i <= countTo; i++)
            {
                int percentDone = (int)(100 * (i / (double)countTo));
                if (percentDone != prevPercentDone)
                {
                    prevPercentDone = percentDone;
                    Console.Write(percentDone.ToString() + "% ");
                }

                k = i;
            }
        });
        Console.WriteLine("");
        Console.WriteLine("Finished asyncTest_count()");
        return k;
    }
 8
Author: Tone Škoda, 2017-07-15 08:03:51

Vê este violino https://dotnetfiddle.net/VhZdLU (e melhorá-lo, se possível) para executar um aplicação simples de consola o que mostra os usos de tarefa, tarefa.Operadores WaitAll(), async e Wait no mesmo programa.

Este violino deve limpar o conceito do ciclo de execução.

Aqui está o código da amostra

using System;
using System.Threading.Tasks;

public class Program
{
    public static void Main()
    {               
        var a = MyMethodAsync(); //Task started for Execution and immediately goes to Line 19 of the code. Cursor will come back as soon as await operator is met       
        Console.WriteLine("Cursor Moved to Next Line Without Waiting for MyMethodAsync() completion");
        Console.WriteLine("Now Waiting for Task to be Finished");       
        Task.WaitAll(a); //Now Waiting      
        Console.WriteLine("Exiting CommandLine");       
    }

    public static async Task MyMethodAsync()
    {
        Task<int> longRunningTask = LongRunningOperation();
        // independent work which doesn't need the result of LongRunningOperationAsync can be done here
        Console.WriteLine("Independent Works of now executes in MyMethodAsync()");
        //and now we call await on the task 
        int result = await longRunningTask;
        //use the result 
        Console.WriteLine("Result of LongRunningOperation() is " + result);
    }

    public static async Task<int> LongRunningOperation() // assume we return an int from this long running operation 
    {
        Console.WriteLine("LongRunningOperation() Started");
        await Task.Delay(2000); // 2 second delay
        Console.WriteLine("LongRunningOperation() Finished after 2 Seconds");
        return 1;
    }   

}

Traço vindo da janela de saída: enter image description here

 6
Author: vibs2006, 2018-01-24 12:45:39
public static void Main(string[] args)
{
    string result = DownloadContentAsync().Result;
    Console.ReadKey();
}

// You use the async keyword to mark a method for asynchronous operations.
// The "async" modifier simply starts synchronously the current thread. 
// What it does is enable the method to be split into multiple pieces.
// The boundaries of these pieces are marked with the await keyword.
public static async Task<string> DownloadContentAsync()// By convention, the method name ends with "Async
{
    using (HttpClient client = new HttpClient())
    {
        // When you use the await keyword, the compiler generates the code that checks if the asynchronous operation is finished.
        // If it is already finished, the method continues to run synchronously.
        // If not completed, the state machine will connect a continuation method that must be executed WHEN the Task is completed.


        // Http request example. 
        // (In this example I can set the milliseconds after "sleep=")
        String result = await client.GetStringAsync("http://httpstat.us/200?sleep=1000");

        Console.WriteLine(result);

        // After completing the result response, the state machine will continue to synchronously execute the other processes.


        return result;
    }
}
 3
Author: Weslley Rufino de Lima, 2018-02-22 15:49:47

Da maneira que eu entendo também, deve haver um terceiro termo adicionado à mistura: {[[0]}.

Async é apenas uma qualificação que você coloca em seu método para dizer que é um método assíncrono.

Task é o retorno da função async. Executa assíncronamente.

Tu await uma tarefa. Quando a execução de código atinge esta linha, o controle salta para trás para o chamador da sua função original circundante.

Se em vez disso, atribuir o retorno de uma função async (ie Task) para uma variável, quando a execução do Código atinge esta linha, apenas continua depois dessa linha na função circundante enquanto o Task executa assíncronamente.

 2
Author: user21306, 2017-06-02 21:15:25

Para a aprendizagem mais rápida..

  • Compreender o fluxo de execução do método( com um diagrama): 3 minutos

  • Pergunta introspecção (sake aprendizagem): 1 min

  • Obter rapidamente através de açúcar de sintaxe: 5 minutos

  • Partilhar a confusão de um programador: 5 minutos

  • Problema: mudar rapidamente uma implementação do Código normal no mundo real para Código Async: 2 minutos

  • Onde Próximo?

Compreender o fluxo de execução do método( com um diagrama): 3 minutos

Nesta imagem, concentra - te no número 6. enter image description here

Na etapa # 6: O acesso à base de dados() ficou sem trabalho que pode fazer sem um resultado de uma tarefa difícil. Assim, o acesso à base utiliza um operador aguardado para suspender o seu progresso e devolver o controlo(rendimento) à pessoa que efectua a chamada. Access thewebasync retorna uma tarefa (de valor de retorno de string) para o chamador. A tarefa representa um prometa produzir um resultado de cadeia. Mas quando responderá a chamada? outra chamada?

([24]) o interlocutor do Access Thewe Basync() não fez nada além de esperar (poderia ter feito algumas tarefas internas e, em seguida, esperou se necessário). Quem ligou está à espera do acesso à base, e o acesso à base está à espera da ligação, neste momento.

Lembre-se, o método já foi devolvido, não pode voltar novamente(Nenhuma segunda vez). Então, como vai saber quem ligou? É tudo sobre Tarefas!A tarefa foi devolvida. a tarefa era aguardada por (não pelo método, não pelo valor). O valor será definido na tarefa. O estado da tarefa será definido para completar. Quem ligou controla a tarefa. Mais leituras para mais tarde aqui.

Pergunta introspecção por aprendizagem: 1 min

Vamos ajustar um pouco a pergunta:

Como e quando utilizar async e await Tasks?

Porque a aprendizagem Task cobre automaticamente o outros 2. Pelo menos para aprender. Claro, esta é uma resposta à sua pergunta sobre async e await.

Obter rapidamente através de açúcar de sintaxe: 5 minutos

  • Antes da conversão

    internal static int Method(int arg0, int arg1) { int result = arg0 + arg1; IO(); // Do some long running IO. return result; }

  • Outro método de tarefa para chamar o método acima

    internal static Task<int> MethodTask(int arg0, int arg1) { Task<int> task = new Task<int>(() => Method(arg0, arg1)); task.Start(); // Hot task (started task) should always be returned. return task; }

Mencionámos esperar ou async? Não. Chame o método acima e você terá uma tarefa. Que podes monitorizar. Você já sabe qual é a tarefa devolucao.. inteiro.
  • Chamar uma tarefa é um pouco complicado. Vamos chamar MethodTask ()

    internal static async Task<int> MethodAsync(int arg0, int arg1) { int result = await HelperMethods.MethodTask(arg0, arg1); return result; }

Estamos à espera que a tarefa esteja terminada. Daí o await. Uma vez que usamos o Wait, devemos usar o async(obrigatório) e o MethodAsync com o async como prefixo (padrão de codificação). Mais leituras para mais tarde aqui

Partilhar a confusão de um programador: 5 minutos

Um desenvolvedor cometeu um erro ao não implementar Mas ainda funciona! Tente entender a pergunta e apenas a resposta aceita fornecida aqui . Espero que tenha lido e entendido completamente. Do mesmo modo, no nosso exemplo, chamar um já construído MethodAsync() é muito mais fácil do que implementar esse método com um Task (MethodTask()) nós mesmos. A maioria dos desenvolvedores acha difícil obter sua cabeça em torno de Tasks ao converter um código para assíncrono.

Dica: tentar encontrar uma implementação async existente (como MethodAsync ou ToListAsync) para terceirizar dificuldade. Então só precisamos lidar com Async e esperar (o que é fácil e muito semelhante ao código normal)

Problema: mudar rapidamente uma implementação do Código normal no mundo real para Operação Async: 2 minutos

A linha de código mostrada abaixo na camada de Dados começou a quebrar(muitos lugares). Porque nós atualizamos alguns de nossos códigos de .net framework 4.2 para .Net core. Tivemos de arranjar isto em 1 hora por toda a aplicação!

var myContract = query.Where(c => c.ContractID == _contractID).First();
Fácil!
  1. EntityFrameWork nuget (it has Queryable Extensions)
  2. namespace = Microsoft.EntityFrameworkCore

O Código foi alterado assim

var myContract = await query.Where(c => c.ContractID == _contractID).FirstAsync();
  1. A assinatura do método mudou de

    Contract GetContract(int contractnumber)

    A

    async Task<Contract> GetContractAsync(int contractnumber)

  2. O Método de chamada também foi afetado: {[21] } foi chamado como GetContractAsync(123456).Result;

  3. Mudámo - lo em todo o lado em 30 minutos. minutos!

Mas o arquitecto disse-nos para não usarmos a Biblioteca do quadro só para isto! oops! drama! Então fizemos uma implementação de tarefas personalizadas. Que tu sabes como. Ainda é fácil!

Para Onde Vamos a seguir? Há um vídeo maravilhoso e rápido que podemos ver sobre a conversão de chamadas síncronas para assíncronas em ASP.Net núcleo , porque é provável que essa seja a direcção que se seguiria depois de ler isto.

 2
Author: Blue Clouds, 2018-09-21 05:09:07

Está a usá-los ao mesmo tempo que cria os tópicos de fundo para executar longos períodos lógica de duração?

Este artigo MDSN: programação assíncrona com async e aguarda (C#) explica explicitamente:

O async e as palavras-chave não fazem com que os tópicos adicionais sejam criado. Os métodos Async não requerem multithreading porque um async o método não funciona por sua própria linha. O método funciona na corrente contexto de sincronização e usa o tempo no tópico apenas quando o o método está activo.

 1
Author: Dmitry G., 2016-10-04 16:16:30

No seguinte código, o método Getbytearrayasync do HttpClient devolve uma tarefa, getContentsTask. A tarefa é uma promessa de produzir a matriz de bytes real quando a tarefa estiver completa. O operador espera é aplicado para obter a tarefa de conteúdo para suspender a execução em SumPageSizesAsync até que a tarefa de conteúdo esteja completa. Entretanto, o controlo é devolvido ao chamador de SumPageSizesAsync. Quando o getContentsTask é terminado, a expressão espera é avaliada para um array de bytes.

private async Task SumPageSizesAsync()
{
    // To use the HttpClient type in desktop apps, you must include a using directive and add a 
    // reference for the System.Net.Http namespace.
    HttpClient client = new HttpClient();
    // . . .
    Task<byte[]> getContentsTask = client.GetByteArrayAsync(url);
    byte[] urlContents = await getContentsTask;

    // Equivalently, now that you see how it works, you can write the same thing in a single line.
    //byte[] urlContents = await client.GetByteArrayAsync(url);
    // . . .
}
 1
Author: lazydeveloper, 2017-08-31 18:40:12

Num nível superior:

1) A Palavra-chave Async permite a espera e é tudo o que faz. A palavra-chave Async não executa o método em um tópico separado. O método f async inicial é executado sincronicamente até que ele atinge espera por uma tarefa demorada.

2) pode esperar por um método que devolve a tarefa ou tarefa do tipo T. não pode esperar pelo método async void.

([2]} 3) o momento em que o principal tópico encontra-se à espera de uma tarefa demorada ou quando o trabalho real é iniciado, o principal o tópico devolve ao chamador do método actual.

4) Se a linha principal vê espera por uma tarefa que ainda está em execução, não espera por ela e retorna para o chamador do método atual. Desta forma, a aplicação continua a responder.

5) Aguarde na tarefa de processamento, irá agora executar em um tópico separado do grupo de threads.

6) Quando esta tarefa estiver terminada, todo o código abaixo será executado pelo tópico separado

Abaixo está a amostra. codigo. Execute-o e verifique o ID do tópico

using System;
using System.Threading;
using System.Threading.Tasks;

namespace AsyncAwaitDemo
{
    class Program
    {
        public static async void AsynchronousOperation()
        {
            Console.WriteLine("Inside AsynchronousOperation Before AsyncMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId);
            //Task<int> _task = AsyncMethod();
            int count = await AsyncMethod();

            Console.WriteLine("Inside AsynchronousOperation After AsyncMethod Before Await, Thread Id: " + Thread.CurrentThread.ManagedThreadId);

            //int count = await _task;

            Console.WriteLine("Inside AsynchronousOperation After AsyncMethod After Await Before DependentMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId);

            DependentMethod(count);

            Console.WriteLine("Inside AsynchronousOperation After AsyncMethod After Await After DependentMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId);
        }

        public static async Task<int> AsyncMethod()
        {
            Console.WriteLine("Inside AsyncMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId);
            int count = 0;

            await Task.Run(() =>
            {
                Console.WriteLine("Executing a long running task which takes 10 seconds to complete, Thread Id: " + Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(20000);
                count = 10;
            });

            Console.WriteLine("Completed AsyncMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId);

            return count;
        }       

        public static void DependentMethod(int count)
        {
            Console.WriteLine("Inside DependentMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId + ". Total count is " + count);
        }

        static void Main(string[] args)
        {
            Console.WriteLine("Started Main method, Thread Id: " + Thread.CurrentThread.ManagedThreadId);

            AsynchronousOperation();

            Console.WriteLine("Completed Main method, Thread Id: " + Thread.CurrentThread.ManagedThreadId);

            Console.ReadKey();
        }

    }
}
 1
Author: ABajpai, 2018-08-05 17:38:51

As respostas aqui são úteis como uma orientação geral sobre aguardar/async. Eles também contêm alguns detalhes sobre como o Wait/async está conectado. Eu gostaria de compartilhar alguma experiência prática com você que você deve saber antes de usar este padrão de design.

O termo "esperar" é literal, por isso, qualquer que seja o fio que lhe chamares, esperará pelo resultado do método antes de continuar. No primeiro plano , isto é um desastre. O tópico principal carrega o fardo de construir o seu aplicativo, incluindo vistas, modelos de visualização, animações iniciais, e qualquer outra coisa que você tem boot-amarrado com esses elementos. Então, quando você espera o primeiro fio, vocêparar a aplicação. O usuário espera e espera quando nada parece acontecer. Isso fornece uma experiência negativa do Usuário.

Você certamente pode esperar por uma linha de fundo usando uma variedade de meios:

Device.BeginInvokeOnMainThread(async () => { await AnyAwaitableMethod(); });

// Notice that we do not await the following call, 
// as that would tie it to the foreground thread.
try
{
Task.Run(async () => { await AnyAwaitableMethod(); });
}
catch
{}

O código completo para estas observações é o seguinte: https://github.com/marcusts/xamarin-forms-annoyances veja a solução chamada AwaitAsyncAntipattern.sln.

O site GitHub também fornece links para uma discussão mais detalhada sobre este tópico.

 0
Author: Stephen Marcus, 2018-04-13 22:47:14

Abaixo está o código que lê o ficheiro excel ao abrir a janela e, em seguida, usa async e espera para executar assíncrono o código que lê uma por uma linha do excel e liga-se à grelha

    namespace EmailBillingRates
{
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        lblProcessing.Text = "";
    }

    private async void btnReadExcel_Click(object sender, EventArgs e)
    {
        string filename = OpenFileDialog();

        Microsoft.Office.Interop.Excel.Application xlApp = new Microsoft.Office.Interop.Excel.Application();
        Microsoft.Office.Interop.Excel.Workbook xlWorkbook = xlApp.Workbooks.Open(filename);
        Microsoft.Office.Interop.Excel._Worksheet xlWorksheet = xlWorkbook.Sheets[1];
        Microsoft.Office.Interop.Excel.Range xlRange = xlWorksheet.UsedRange;
        try
        {
            Task<int> longRunningTask = BindGrid(xlRange);
            int result = await longRunningTask;

        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message.ToString());
        }
        finally
        {
            //cleanup  
           // GC.Collect();
            //GC.WaitForPendingFinalizers();

            //rule of thumb for releasing com objects:  
            //  never use two dots, all COM objects must be referenced and released individually  
            //  ex: [somthing].[something].[something] is bad  

            //release com objects to fully kill excel process from running in the background  
            Marshal.ReleaseComObject(xlRange);
            Marshal.ReleaseComObject(xlWorksheet);

            //close and release  
            xlWorkbook.Close();
            Marshal.ReleaseComObject(xlWorkbook);

            //quit and release  
            xlApp.Quit();
            Marshal.ReleaseComObject(xlApp);
        }

    }

    private void btnSendEmail_Click(object sender, EventArgs e)
    {

    }

    private string OpenFileDialog()
    {
        string filename = "";
        OpenFileDialog fdlg = new OpenFileDialog();
        fdlg.Title = "Excel File Dialog";
        fdlg.InitialDirectory = @"c:\";
        fdlg.Filter = "All files (*.*)|*.*|All files (*.*)|*.*";
        fdlg.FilterIndex = 2;
        fdlg.RestoreDirectory = true;
        if (fdlg.ShowDialog() == DialogResult.OK)
        {
            filename = fdlg.FileName;
        }
        return filename;
    }

    private async Task<int> BindGrid(Microsoft.Office.Interop.Excel.Range xlRange)
    {
        lblProcessing.Text = "Processing File.. Please wait";
        int rowCount = xlRange.Rows.Count;
        int colCount = xlRange.Columns.Count;

        // dt.Column = colCount;  
        dataGridView1.ColumnCount = colCount;
        dataGridView1.RowCount = rowCount;

        for (int i = 1; i <= rowCount; i++)
        {
            for (int j = 1; j <= colCount; j++)
            {
                //write the value to the Grid  
                if (xlRange.Cells[i, j] != null && xlRange.Cells[i, j].Value2 != null)
                {
                     await Task.Delay(1);
                     dataGridView1.Rows[i - 1].Cells[j - 1].Value =  xlRange.Cells[i, j].Value2.ToString();
                }

            }
        }
        lblProcessing.Text = "";
        return 0;
    }
}

internal class async
{
}

} `

 0
Author: Zaheer Abbas, 2018-04-26 10:51:54

Async / Await

Acctualmente Async / wait são um par de palavras-chave que são apenas açúcar sintático para criar uma chamada de volta de uma tarefa assíncrona.

Tome por exemplo esta operação:

    public static void DoSomeWork()
    {
        var task = Task.Run(() =>
        {
            // [RUNS ON WORKER THREAD]

            // IS NOT bubbling up due to the different threads
            throw new Exception();
            Thread.Sleep(2000);

            return "Hello";
        });

        // This is the callback
        task.ContinueWith((t) => {
            // -> Exception is swallowed silently
            Console.WriteLine("Completed");

            // [RUNS ON WORKER THREAD]
        });
    }
Este método tem desvantagens Servais. Erros não são passados e é extremamente difícil de ler. Mas Async e aguarda para nos ajudar.
    public async static void DoSomeWork()
    {
        var result = await Task.Run(() =>
        {
            // [RUNS ON WORKER THREAD]

            // IS bubbling up
            throw new Exception();
            Thread.Sleep(2000);

            return "Hello";
        });

        // every thing below is a callback 
        // (including the calling methods)

        Console.WriteLine("Completed");

    }
A espera de chamadas tem de estar nos métodos Async. Isto tem algumas vantagens:
  • Devolve o resultado
  • cria automaticamente uma resposta
  • verifica os erros e deixa-os borbulhar em callstack (só até ninguém-aguarda as chamadas em callstack)
  • espera pelo resultado
  • liberta o fio principal
  • executa a chamada de volta na linha principal
  • usa um fio de trabalho da fossa para a tarefa
  • torna o código fácil de ler
  • e muito mais

Nota : Async e Wait são usados com chamadas assíncronas não para fazer estas. Você tem que usar tarefa Libary para isso, como tarefa.Executar() .

Aqui está uma comparação entre esperar e ninguém esperar por soluções.

Esta é a solução de nenhuma async:

    public static long DoTask()
    {
        stopWatch.Reset();
        stopWatch.Start();

        // [RUNS ON MAIN THREAD]
        var task = Task.Run(() => {
            Thread.Sleep(2000);
            // [RUNS ON WORKER THREAD]
        });
        Thread.Sleep(1000);
        // goes directly further
        // WITHOUT waiting until the task is finished

        // [RUNS ON MAIN THREAD]

        stopWatch.Stop();
        // 50 milliseconds
        return stopWatch.ElapsedMilliseconds;
    }

Este é o método async:

    public async static Task<long> DoAwaitTask()
    {
        stopWatch.Reset();
        stopWatch.Start();

        // [RUNS ON MAIN THREAD]

        await Task.Run(() => {
            Thread.Sleep(2000);
            // [RUNS ON WORKER THREAD]
        });
        // Waits until task is finished

        // [RUNS ON MAIN THREAD]

        stopWatch.Stop();
        // 2050 milliseconds
        return stopWatch.ElapsedMilliseconds;
    }

Pode chamar de facto um método async sem a palavra-chave aguardar, mas isto significa que qualquer excepção aqui é engolida no modo de libertação:

    public static Stopwatch stopWatch { get; } = new Stopwatch();

    static void Main(string[] args)
    {
        Console.WriteLine("DoAwaitTask: " + DoAwaitTask().Result + " ms");
        // 2050 (2000 more because of the await)
        Console.WriteLine("DoTask: " + DoTask() + " ms");
        // 50
        Console.ReadKey();
    }
Async e Wait não são para paralelos. computacao. Eles são usados para não bloquear o seu fio principal. Se for sobre asp.net ou aplicações windows. Bloquear o seu tópico principal devido a uma chamada de rede é uma coisa má. Se fizer isto, o seu aplicativo ficará sem resposta ou pode cair.

Confira ms docs para obter alguns exemplos.

Espero que isto ajude.
 0
Author: Hakim, 2018-09-27 17:45:43