async + aguardar == sincronizar?

24

Tropecei neste post que fala sobre fazer solicitações da Web assíncronas.

Agora, a simplicidade à parte, se no mundo real, tudo o que você faz é fazer uma solicitação assíncrona e aguardá-la na próxima linha, não é o mesmo que fazer uma chamada de sincronização em primeiro lugar?

Mrchief
fonte
5
Não exatamente. Seu código é síncrono no sentido de que nada acontece até você obter um resultado. No entanto, por baixo, você provavelmente desistiu do segmento em que estava executando até o retorno do método assíncrono e recebeu outro segmento para continuar executando.
R0MANARMY 14/01
2
que é, mas com async você pode fazer outra assíncrona ao mesmo tempo e, em seguida, aguardar a 2, com sincronização isso não é possível
catraca aberração
Aqui está um artigo ( tomasp.net/blog/async-compilation-internals.aspx ) discutindo alguns dos segredos do assíncrono em C # - faz parte de uma série que aborda a programação assíncrona em C # e F #.
paul
@ratchetfreak: Sim, isso sem dizer se você está fazendo várias chamadas.
Mrchief
@ R0MANARMY: Se o seu aplicativo estiver fazendo outras coisas, sim e o async + waiting permite isso. Akim diz o melhor! Mas imagine que o código não esteja no manipulador button_click ou em qualquer manipulador de eventos desse tipo. Se alguém copiar o código cegamente (assíncrono + linhas de espera), para qualquer método, isso pode causar uma falsa impressão de que seu código é assíncrono, mas pode não ser.
Mrchief

Respostas:

32

Não, async + await != syncpor causa da continuação

Do MSDN 'Programação assíncrona com Async e Await (C # e Visual Basic)'

Os métodos assíncronos devem ser operações sem bloqueio. Uma expressão de espera em um método assíncrono não bloqueia o encadeamento atual enquanto a tarefa aguardada está em execução. Em vez disso, a expressão inscreve o restante do método como uma continuação e retorna o controle para o chamador do método assíncrono .

Por exemplo, a execução assíncrona não bloqueará o thread da interface do usuário e Some TextBox.Textserá atualizada após a conclusão do download

private async void OnButtonClick()
{
   SomeTextBox.Text = await new WebClient().DownloadStringTaskAsync("http://stackoverflow.com/");
}
Akim
fonte
Muito bem dito!
Mrchief
Você poderia explicar com mais detalhes? Você está dizendo ... que sem isso ... você não seria capaz de interagir com a interface do usuário ... pois isso estaria no thread principal. Isso significa que isso só se torna aplicável em um programa de tipo de aplicativo destinado à web em que a interação é separada do encadeamento do servidor da web. Portanto, em uma casca de noz, isso só se torna importante, ou seja, não é sincronizado * quando o thread principal é o thread em execução. Isso não criaria um comportamento inesperado, ou seja, em um aplicativo (1 segmento principal), dois botões foram clicados .. mas você deve poder clicar no 1 sem a primeira conclusão?
Seabizkit
Que tal Console.WriteLine(await GetStringOverNetwork());? E se você precisar da saída da chamada assíncrona? O programa seria bloqueado no primeiro acesso, mesmo que o encadeamento pudesse continuar com a execução?
Andrew
6

Não, não é o mesmo.

Seu asyncbloco de código está aguardando o awaitretorno da chamada para continuar, no entanto, o restante do seu aplicativo não está esperando e ainda pode continuar normalmente.

Por outro lado, uma chamada síncrona faria todo o aplicativo ou thread aguardar até que o código terminasse a execução para continuar com qualquer outra coisa.

Rachel
fonte
a chamada de sincronização não pôde ser implementada enquanto async + aguarda?
ratchet freak
@ratchetfreak Eu acho que há alguma sobrecarga na configuração de aguardar / assíncrona, então eu não acho que você queira codificar todo o aplicativo com ele. Eu o uso apenas para executar blocos de código potencialmente demorados, para não bloquear meus aplicativos. :)
Rachel
5

Por favor, permita-me esclarecer as coisas em relação ao assíncrono / aguardar.

Quando aguardar, a máquina de estado subjacente permite que o controle seja retornado imediatamente. Então, quando a chamada esperada for concluída, a máquina de estado subjacente permitirá que a execução continue na linha após a chamada aguardada.

Portanto, o bloco assíncrono não está bloqueado nem está aguardando o término da chamada esperada; O controle é retornado imediatamente quando o comando de espera é encontrado.

A máquina de estado subjacente faz parte da "mágica" por trás do uso de async / wait que não é desutilizada e perdida.

Cedric Harris
fonte
2

Eu tropecei nisso com a mesma pergunta em mente, mas depois de ler as respostas, a pergunta parece persistir, confusa com as referências à "mágica escondida".

Na programação assíncrona mencionada acima :

  • A asyncpalavra-chave transforma um método em um método assíncrono, que permite usar a awaitpalavra - chave em seu corpo.
  • Quando a awaitpalavra-chave é aplicada, ela suspende o método de chamada e retorna o controle ao chamador até que a tarefa esperada seja concluída.
  • awaitsó pode ser usado dentro de um asyncmétodo.

O contexto encontrado encontra- awaitse bloqueado?

  • Sim . Essa é essencialmente uma barreira de sincronização local para manter um estado conhecido no contexto da execução; exceto que outros contextos, se houver, não são unidos.

O restante do aplicativo bloqueia no await?

  • Depende de como seu aplicativo foi gravado. Se houver uma série de awaittarefas ed dependentes iniciadas sequencialmente no mesmo contexto (consulte: Tentando entender algum comportamento assíncrono / aguardar )

    await asyncCall1();
    await asyncCall2();  // waits for asyncCall1() to complete

    Dessa maneira, cada um awaitdeles bloquearia a desova do próximo.

    Por outro lado, as mesmas tarefas dependentes lançadas em paralelo seriam executadas em paralelo e o contexto seria bloqueado apenas nas respectivas. await:

    Task<int> t1 = asyncCall1();
    Task<string> t2 = asyncCall2();  // runs in parallel with asyncCall1()
    int val = await t1;
    string str = await t2;  // waits for asyncCall1() to complete

    Em geral, a awaitexecução gera o contexto externo, de onde o contexto atual é chamado. No entanto, se o contexto externo em si está aguardando a corrente, é como um awaits seqüencial no mesmo contexto.

Portanto, para colher os asyncbenefícios, é necessário projetar o aplicativo para executar vários contextos paralelos (interface do usuário, cliente de dados etc.) e, awaitem um contexto, gerar execução para outros contextos, para que o aplicativo inteiro não bloqueie um indivíduo await.

oversynched
fonte