Pergunta

Por alguma razão, há uma pausa após o início do programa. Acredito que WebClient().DownloadStringTaskAsync() é a causa.

class Program
{
    static void Main(string[] args)
    {
        AsyncReturnTask();

        for (int i = 0; i < 15; i++)
        {
            Console.WriteLine(i);
            Thread.Sleep(100);
        }
    }

    public static async void AsyncReturnTask()
    {
        var result = await DownloadAndReturnTaskStringAsync();
        Console.WriteLine(result);
    }

    private static async Task<string> DownloadAndReturnTaskStringAsync()
    {
        return await new WebClient().DownloadStringTaskAsync(new Uri("http://www.weather.gov"));
    }
}

Tanto quanto eu entendo, meu programa deve começar a contar de 0 a 15 imediatamente. Estou fazendo algo errado?

Eu tive o mesmo problema com a amostra original de download da Netflix (que você obtém com CTP) - Depois de pressionar o botão de pesquisa, a UI primeiro congela - e depois de algum tempo, ele responde ao carregar os próximos filmes. E acredito que não congelou na apresentação de Anders Hejlsberg no PDC 2010.

Mais uma coisa. Quando em vez de

return await new WebClient().DownloadStringTaskAsync(new Uri("http://www.weather.gov"));

Eu uso meu próprio método:

return await ReturnOrdinaryTask();

Qual é:

public static Task<string> ReturnOrdinaryTask()
{
    var t = Task.Factory.StartNew(() =>
    {
        for (int i = 0; i < 10; i++)
        {
            Console.WriteLine("------------- " + i.ToString());
            Thread.Sleep(100);
        }
        return "some text";
    });
    return t;
}

Funciona como deveria. Quero dizer, não carrega nada, mas começa imediatamente e não bloqueia o fio principal, enquanto faz seu trabalho.

Editar

Ok, o que eu acredito agora é: o WebClient.DownloadStringTaskAsync A função está estragada. Deve funcionar sem o período inicial de bloqueio, assim:

    static void Main(string[] args)
    {
        WebClient cli = new WebClient();
        Task.Factory.StartNew(() =>
            {
                cli.DownloadStringCompleted += (sender, e) => Console.WriteLine(e.Result);
                cli.DownloadStringAsync(new Uri("http://www.weather.gov"));
            });

        for (int i = 0; i < 100; i++)
        {
            Console.WriteLine(i);
            Thread.Sleep(100);
        }
    }
Foi útil?

Solução

Embora o seu programa bloqueie por um tempo, ele retoma a execução no loop for, antes que o resultado seja retornado do servidor remoto.

Lembre-se de que a nova API assíncrona ainda é um thread único. Então WebClient().DownloadStringTaskAsync() ainda precisa ser executado em seu tópico até que a solicitação tenha sido preparada e enviada ao servidor, antes que ele possa await e render a execução de volta ao fluxo do seu programa em Main ().

Eu acho que os resultados que você está vendo são devido ao fato de levar algum tempo para criar e enviar a solicitação da sua máquina. Primeiro quando isso terminar, a implementação de DownloadStringTaskAsync Pode aguardar a conclusão da IO da rede e do servidor remoto e pode retornar a execução a você.

Por outro lado, seu RunOrdinaryTask O método apenas inicializa uma tarefa e fornece uma carga de trabalho e diz para iniciar. Então ele retorna imediatamente. É por isso que você não vê um atraso ao usar RunOrdinaryTask.

Aqui estão alguns links sobre o assunto: Blog de Eric Lippert (um dos designers de idiomas), bem como Postagem inicial do blog de Jon Skeet sobre isso. Eric tem uma série de 5 posts sobre o estilo de passagem de continuação, que realmente é o que async e await é realmente sobre. Se você deseja entender o novo recurso em detalhes, pode ler as postagens de Eric sobre CPS e Async. De qualquer forma, ambos os links acima fazem um bom trabalho ao explicar um fato muito importante:

  • Assíncrono! = Paralelo

Em outras palavras, async e await Não gira novos threads para você. Eles apenas permitem retomar a execução do seu fluxo normal, quando você está fazendo uma operação de bloqueio - vezes em que sua CPU apenas se senta e não fazia nada em um programa síncrono, aguardando a conclusão de alguma operação externa.

Editar

Só para ficar claro sobre o que está acontecendo: DownloadStringTaskAsync configura uma continuação e depois liga WebClient.DownloadStringAsync, no mesmo tópico, e então rende a execução de volta ao seu código. Portanto, o tempo de bloqueio que você está vendo antes que o loop comece a contar, é o tempo que leva DownloadStringAsync completar. Seu programa com assíncrona e aguardar está muito perto de ser o equivalente ao programa a seguir, que exibe o mesmo comportamento que seu programa: um bloco inicial, depois a contagem começa e em algum lugar do meio, o Async Op termina e imprime o conteúdo do A URL solicitada:

    static void Main(string[] args)
    {
        WebClient cli = new WebClient();
        cli.DownloadStringCompleted += (sender, e) => Console.WriteLine(e.Result);
        cli.DownloadStringAsync(new Uri("http://www.weather.gov")); // Blocks until request has been prepared

        for (int i = 0; i < 15; i++)
        {
            Console.WriteLine(i);
            Thread.Sleep(100);
        }
    }

Nota: Não sou de forma alguma um especialista nesse assunto, então posso estar errado em alguns pontos. Sinta -se à vontade para corrigir minha compreensão do assunto, se você acha que isso está errado - apenas olhei para a apresentação do PDC e joguei com o CTP na noite passada.

Outras dicas

Tem certeza de que o problema não está relacionado às configurações de proxy que estão sendo detectadas no IE/Registry/Somewhere Slow?

Tente definir webclient.proxy = nulo (ou especificar configurações no app.config) e seu período de "bloqueio" deve ser mínimo.

Você está pressionando F5 ou CTLR+F5 para executá -lo? Com F5, há um atraso para vs apenas para procurar os símbolos para asyncctplibrary.dll ...

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top