Comment puis-je attendre que la tâche soit terminée en C#?

je veux envoyer une requête à un serveur et des processus la valeur retournée:

private static string Send(int id)
{
    Task<HttpResponseMessage> responseTask = client.GetAsync("aaaaa");
    string result = string.Empty;
    responseTask.ContinueWith(x => result = Print(x));
    responseTask.Wait(); // it doesn't wait for the completion of the response task
    return result;
}

private static string Print(Task<HttpResponseMessage> httpTask)
{
    Task<string> task = httpTask.Result.Content.ReadAsStringAsync();
    string result = string.Empty;
    task.ContinueWith(t =>
    {
        Console.WriteLine("Result: " + t.Result);
        result = t.Result;
    });
    task.Wait();  // it does wait
    return result;
}

Est - ce que j'utilise Task correctement? Je ne le pense pas, parce que le Send() retourne la méthode string.Empty tous les temps, tandis que Print renvoie la valeur correcte.

Qu'est-ce que je fais de mal? Comment obtenir le bon résultat d'un serveur?

25
demandé sur Armand Delessert 2012-11-03 20:56:30

6 réponses

votre méthode D'impression a probablement besoin d'attendre la fin de la suite (ContinueWith renvoie une tâche que vous pouvez attendre). Sinon le deuxième ReadAsStringAsync finit, la méthode retourne (avant que le résultat soit assigné dans la suite). Même problème existe dans votre méthode d'envoi. Les deux ont besoin d'attendre la suite pour obtenir systématiquement les résultats que vous voulez. Semblable à ci-dessous

private static string Send(int id)
{
    Task<HttpResponseMessage> responseTask = client.GetAsync("aaaaa");
    string result = string.Empty;
    Task continuation = responseTask.ContinueWith(x => result = Print(x));
    continuation.Wait();
    return result;
}

private static string Print(Task<HttpResponseMessage> httpTask)
{
    Task<string> task = httpTask.Result.Content.ReadAsStringAsync();
    string result = string.Empty;
    Task continuation = task.ContinueWith(t =>
    {
        Console.WriteLine("Result: " + t.Result);
        result = t.Result;
    });
    continuation.Wait();  
    return result;
}
24
répondu Kenneth Ito 2012-11-03 17:31:21

Il attend client.GetAsync("aaaaa");, mais ne pas attendre result = Print(x)

responseTask.ContinueWith(x => result = Print(x)).Wait()

--EDIT--

Task responseTask = Task.Run(() => { 
    Thread.Sleep(1000); 
    Console.WriteLine("In task"); 
});
responseTask.ContinueWith(t=>Console.WriteLine("In ContinueWith"));
responseTask.Wait();
Console.WriteLine("End");

code ci-Dessus n'est pas garantie de la sortie:

In task
In ContinueWith
End

mais c'est le cas (voir newTask)

Task responseTask = Task.Run(() => { 
    Thread.Sleep(1000); 
    Console.WriteLine("In task"); 
});
Task newTask = responseTask.ContinueWith(t=>Console.WriteLine("In ContinueWith"));
newTask.Wait();
Console.WriteLine("End");
5
répondu L.B 2012-11-03 17:56:42

je suis un novice async, donc je ne peux pas vous dire définitivement ce qui se passe ici. Je soupçonne qu'il y a une inadéquation dans les attentes d'exécution de la méthode, même si vous utilisez des tâches en interne dans les méthodes. Je pense que vous obtiendriez les résultats que vous attendez si vous changez L'impression pour retourner une tâche:

private static string Send(int id)
{
    Task<HttpResponseMessage> responseTask = client.GetAsync("aaaaa");
    Task<string> result;
    responseTask.ContinueWith(x => result = Print(x));
    result.Wait();
    responseTask.Wait(); // There's likely a better way to wait for both tasks without doing it in this awkward, consecutive way.
    return result.Result;
}

private static Task<string> Print(Task<HttpResponseMessage> httpTask)
{
    Task<string> task = httpTask.Result.Content.ReadAsStringAsync();
    string result = string.Empty;
    task.ContinueWith(t =>
    {
        Console.WriteLine("Result: " + t.Result);
        result = t.Result;
    });
    return task;
}
0
répondu Jacob Proffitt 2012-11-03 17:24:14

en travaillant avec des continuations je trouve utile de penser à l'endroit où j'écris .Continue comme le lieu à partir duquel l'exécution continue immédiatement aux déclarations qui la suivent, pas les déclarations "à l'intérieur" elle. Dans ce cas, il devient évident que vous obtenez une chaîne vide est retournée en Envoyer. Si votre seul traitement de la réponse est de l'écrire à la console, vous n'avez pas besoin d'attendre dans la solution D'Ito - l'impression de la console se fera sans attendre mais à la fois Envoyer et imprimer doit retourner nulle dans ce cas. Exécutez cette application console et vous aurez l'impression de la page.

l'OMI, de l'attente et de la Tâche.Les appels de résultat (quel bloc) sont parfois nécessaires, en fonction de votre débit de contrôle désiré, mais le plus souvent ils sont un signe que vous n'utilisez pas vraiment la fonctionnalité asynchrone correctement.

namespace TaskTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Send();
            Console.WriteLine("Press Enter to exit");
            Console.ReadLine();
        }

        private static void Send()
        {
            HttpClient client = new HttpClient();
            Task<HttpResponseMessage> responseTask = client.GetAsync("http://google.com");
            responseTask.ContinueWith(x => Print(x));
        }

        private static void Print(Task<HttpResponseMessage> httpTask)
        {
            Task<string> task = httpTask.Result.Content.ReadAsStringAsync();
            Task continuation = task.ContinueWith(t =>
            {
                Console.WriteLine("Result: " + t.Result);
            });
        }
    }
}
0
répondu Tony 2012-11-05 05:23:42
async Task<int> AccessTheWebAsync()  
{   
    // You need to add a reference to System.Net.Http to declare client.  
    HttpClient client = new HttpClient();  

    // GetStringAsync returns a Task<string>. That means that when you await the  
    // task you'll get a string (urlContents).  
    Task<string> getStringTask = 

    client.GetStringAsync("http://msdn.microsoft.com");  

    // You can do work here that doesn't rely on the string from GetStringAsync.  
    DoIndependentWork();  

    // The await operator suspends AccessTheWebAsync.  
    //  - AccessTheWebAsync can't continue until getStringTask is complete.  
    //  - Meanwhile, control returns to the caller of AccessTheWebAsync.  
    //  - Control resumes here when getStringTask is complete.   
    //  - The await operator then retrieves the string result from 
    getStringTask.  
    string urlContents = await getStringTask;  

    // The return statement specifies an integer result.  
    // Any methods that are awaiting AccessTheWebenter code hereAsync retrieve the length 
    value.  
    return urlContents.Length;  
}  
0
répondu Nainesh Patel 2018-04-24 16:53:02

un exemple propre qui répond au titre

string output = "Error";
Task task = Task.Factory.StartNew(() =>
{
    System.Threading.Thread.Sleep(2000);
    output = "Complete";
});

task.Wait();
Console.WriteLine(output);
0
répondu vikingfabian 2018-10-06 07:44:31