Pergunta

Alguém pode explicar o que o await função?

Foi útil?

Solução

Eles apenas falei sobre isso no PDC ontem!

Aguarda é usado em conjunto com tarefas (programação paralela) no .NET. É uma palavra -chave que está sendo introduzida na próxima versão do .NET. Mais ou menos, permite que você "pause" a execução de um método para aguardar a tarefa concluir a execução. Aqui está um breve exemplo:

//create and run a new task  
Task<DataTable> dataTask = new Task<DataTable>(SomeCrazyDatabaseOperation);

//run some other code immediately after this task is started and running  
ShowLoaderControl();  
StartStoryboard();

//this will actually "pause" the code execution until the task completes.  It doesn't lock the thread, but rather waits for the result, similar to an async callback  
// please so also note, that the task needs to be started before it can be awaited. Otherwise it will never return
dataTask.Start();
DataTable table = await dataTask;

//Now we can perform operations on the Task result, as if we're executing code after the async operation completed  
listBoxControl.DataContext = table;  
StopStoryboard();  
HideLoaderControl();

Outras dicas

Basicamente, o async e await Palavras -chave permitem especificar que a execução de um método deve parar em todos os usos de await, que marcam o método assíncrono chama e depois retomam assim que a operação assíncrona estiver concluída. Isso permite chamar um método no encadeamento principal de um aplicativo e lidar com o trabalho complexo de forma assíncrona, sem a necessidade de definir explicitamente encadeamentos e se unir ou bloquear o thread principal do aplicativo.

Pense nisso como sendo um pouco semelhante a um yield return declaração em um método que produz um ienumerable. Quando o tempo de execução atinge o yield, basicamente salvará o estado atual do método e retornará o valor ou referência que está sendo rendido. Na próxima vez que o iEnumerator.MoveNext () for chamado no objeto de retorno (que é gerado internamente pelo tempo de execução), o estado antigo do método é restaurado na pilha e a execução continua com a próxima linha após o yield return Como se nunca tivéssemos deixado o método. Sem essa palavra-chave, um tipo de iEnumerator deve ser definido sob medida para armazenar o estado e lidar com as solicitações de iteração, com métodos que podem se tornar realmente muito complexos.

Da mesma forma, um método marcado como async Deve ter pelo menos um await. Em um await, o tempo de execução salvará o estado do thread atual e a pilha de chamadas, fará a chamada assíncrona e relaxará de volta ao loop de mensagem do tempo de execução para lidar com a próxima mensagem e manter o aplicativo responsivo. Quando a operação assíncrona é concluída, na próxima oportunidade de agendamento, a pilha de chamadas para aumentar a operação assíncrona é empurrada de volta e continuou como se a chamada fosse síncrona.

Então, essas duas novas palavras -chave simplificam basicamente a codificação de processos assíncronos, como yield return simplificou a geração de enumeres personalizados. Com algumas palavras-chave e um pouco de conhecimento em segundo plano, você pode pular todos os detalhes confusos e frequentemente propensos a erros de um padrão assíncrono tradicional. Isso será inestimável em praticamente qualquer aplicativo de GUI orientado a eventos como WinForms, WPF do Silverlight.

A resposta atualmente aceita é enganosa.await não está pausando nada. Primeiro de tudo, ele pode ser usado apenas em métodos ou lambdas marcados como async e retornando Task ou void Se você não se importa com Task instância em execução neste método.

Aqui está uma ilustração:

internal class Program
{
    private static void Main(string[] args)
    {
        var task = DoWork();
        Console.WriteLine("Task status: " + task.Status);
        Console.WriteLine("Waiting for ENTER");
        Console.ReadLine();
    }

    private static async Task DoWork()
    {
        Console.WriteLine("Entered DoWork(). Sleeping 3");
        // imitating time consuming code
        // in a real-world app this should be inside task, 
        // so method returns fast
        Thread.Sleep(3000);

        await Task.Run(() =>
            {
                for (int i = 0; i < 10; i++)
                {
                    Console.WriteLine("async task iteration " + i);
                    // imitating time consuming code
                    Thread.Sleep(1000);
                }
            });

        Console.WriteLine("Exiting DoWork()");
    }
}

Resultado:

Entrou dowork (). Dormindo 3
iteração de tarefa assíncrona 0
Status da tarefa: WaitingForAcativation
Esperando por entrar
iteração de tarefa assíncrona 1
iteração de tarefa assíncrona 2
iteração de tarefa assíncrona 3
iteração de tarefa assíncrona 4
iteração de tarefa assíncrona 5
iteração de tarefa assíncrona 6
iteração de tarefa assíncrona 7
iteração de tarefa assíncrona 8
iteração de tarefa assíncrona 9
Saindo dowork ()

Para qualquer pessoa nova em programação assíncrona no .NET, aqui está uma analogia (totalmente falsa) em um cenário com o qual você pode estar mais familiarizado - chamadas de Ajax usando JavaScript/JQuery. Um post simples de jQuery Ajax se parece com o seguinte:

$.post(url, values, function(data) {
  // AJAX call completed, do something with returned data here
});

O motivo pelo qual processamos os resultados em uma função de retorno de chamada é, portanto, não bloqueamos o encadeamento atual enquanto aguardamos a chamada do AJAX para retornar. Somente quando a resposta estiver pronta, o retorno de chamada será demitido, liberando o thread atual para fazer outras coisas nesse meio tempo.

Agora, se JavaScript apoiou o await palavra -chave (o que é claro que nãoainda!)), você pode alcançar o mesmo com isso:

var data = await $.post(url, values);
// AJAX call completed, do something with returned data here

Isso é muito mais limpo, mas com certeza parece que introduzimos o código síncrono e de bloqueio. Mas o compilador (falso) JavaScript teria levado tudo depois await e conectou -o a um retorno de chamada, então, em tempo de execução, o segundo exemplo se comportaria como o primeiro.

Pode não parecer que está economizando muito trabalho, mas quando se trata de coisas como contextos de manuseio de exceções e sincronização, o compilador está realmente fazendo um muito de levantamento pesado para você. Para mais, eu recomendo o Perguntas frequentes Seguido por Série de blogs de Stephen Cleary.

Se eu tivesse que implementá -lo em Java, seria algo assim:

/**
 * @author Ilya Gazman
 */
public abstract class SynchronizedTask{

    private ArrayList<Runnable> listeners = new ArrayList<Runnable>();

    private static final ThreadPoolExecutor threadPoolExecutor =  new ThreadPoolExecutor(6, 6, 0, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(1000));

    public final void await(Runnable listener){
        synchronized (this) {
            listeners.add(listener);
        }
    }

    public void excecute(){
        onExcecute();
        for (int i = listeners.size() - 1; i >= 0; i--) {
            Runnable runnable;
            synchronized (this) {
                runnable = listeners.remove(i);
            }
            threadPoolExecutor.execute(runnable);
        }
    }

    protected abstract void onExcecute();
}

Seu aplicativo usaria assim:

public class Test{
    private Job job = new Job();

    public Test() {
        craeteSomeJobToRunInBackground();
        methode1();
        methode2();
    }

    private void methode1(){
        System.out.println("Running methode 1");
        job.await(new Runnable() {

            @Override
            public void run() {
                System.out.println("Continue to running methode 1");
            }
        });
    }

    private void methode2(){
        System.out.println("Running methode 2");
    }

    private void craeteSomeJobToRunInBackground() {
        new Thread(new Runnable() {

            @Override
            public void run() {
                job.excecute();
            }
        }).start();
    }

    private class Job extends SynchronizedTask{

        @Override
        protected void onExcecute() {
            try {
                Thread.sleep(1000);
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Job is done");
        }
    }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top