Подтвердить что ты не робот

Как подождать завершения задачи на С#?

Я хочу отправить запрос на сервер и обработать возвращаемое значение:

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;
    }

Я правильно использую Task? Я так не думаю, потому что метод Send() возвращает string.Empty каждый раз, а Print возвращает правильное значение.

Что я делаю неправильно? Как получить правильный результат с сервера?

4b9b3361

Ответ 1

Ваш метод печати, вероятно, должен ждать завершения продолжения (ContinueWith возвращает задачу, которую вы можете подождать). В противном случае завершается вторая ReadAsStringAsync, метод возвращает (до того, как результат будет назначен в продолжении). Такая же проблема существует в методе отправки. Оба должны ждать продолжения, чтобы последовательно получать нужные результаты. Как показано ниже

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;
}

Ответ 2

Ожидает client.GetAsync("aaaaa");, но не ждет 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");

Выше код не гарантирует вывод:

In task
In ContinueWith
End

Но это происходит (см. 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");

Ответ 3

Я начинаю асинхронно, поэтому я не могу точно сказать, что здесь происходит. Я подозреваю, что существует несоответствие ожиданий выполнения метода, хотя вы используете внутренние задачи в методах. Я думаю, вы получите ожидаемые результаты, если измените Print, чтобы вернуть Task <string> :

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 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;
}

Ответ 4

При работе с продолжениями я считаю полезным подумать о том месте, где я пишу. Продолжить. В качестве места, из которого выполнение немедленно продолжает выполняемые за ним утверждения, а не выражения внутри. В этом случае становится ясно, что вы получите пустую строку, возвращаемую в Send. Если ваша обработка только ответа на запись на консоль, вам не нужно какое-либо решение Wait in Ito - распечатка консоли произойдет без ожидания, но оба Send и Print должны вернуть void в этом случае. Запустите это в консольном приложении, и вы получите распечатку страницы.

IMO, ждет и Task.Result звонки (какой блок) необходимы иногда, в зависимости от вашего желаемого потока управления, но чаще они являются признаком того, что вы действительно не используете асинхронные функции правильно.

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);
            });
        }
    }
}