web-dev-qa-db-fra.com

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

Je souhaite envoyer une demande à un serveur et traiter la valeur renvoyé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 pense pas, car la méthode Send() renvoie string.Empty à chaque fois, alors que Print renvoie la valeur correcte.

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

28
user266003

Votre méthode Print doit probablement attendre la fin de la suite (ContinueWith renvoie une tâche que vous pouvez attendre). Sinon, la seconde ReadAsStringAsync se termine, la méthode retourne (avant que le résultat ne soit affecté dans la suite). Le même problème existe dans votre méthode d'envoi. Les deux doivent attendre la suite pour obtenir systématiquement les résultats souhaités. Similaire à 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;
}
27
Kenneth Ito

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

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

--MODIFIER--

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

Le code ci-dessus ne garantit pas la sortie:

In task
In ContinueWith
End

Mais ceci fait (voir la 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");
6
L.B

Lorsque je travaille avec des continuations, je trouve utile de penser à l’endroit où j’écris .ContinueAvec l’endroit à partir duquel l’exécution continue immédiatement aux instructions qui la suivent, et non à l’intérieur. Dans ce cas, il est clair que vous obtiendrez une chaîne vide dans Envoyer. Si votre seul traitement de la réponse est l'écriture sur la console, vous n'avez besoin d'aucune solution Wait in Ito - l'impression de la console se fera sans attente, mais les deux commandes Envoyer et Imprimer doivent être annulées dans ce cas. Exécutez cette application dans la console et vous obtiendrez une impression de la page.

Les appels IMO, les attentes et les appels Task.Result (quel bloc) sont parfois nécessaires, en fonction du flux de contrôle souhaité, mais ils indiquent le plus souvent que vous n'utilisez pas correctement les fonctionnalités asynchrones.

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
Tony
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
Nainesh Patel

Je suis un novice async, donc je ne peux pas vous dire de façon définitive ce qui se passe ici. Je soupçonne que les attentes d'exécution des méthodes ne correspondent pas, même si vous utilisez des tâches en interne dans les méthodes. Je pense que vous obtiendriez les résultats escomptés si vous changiez Print pour retourner une tâche <chaîne>:

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
Jacob Proffitt

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
vikingfabian