Как подождать завершения задачи на С#?
Я хочу отправить запрос на сервер и обработать возвращаемое значение:
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
возвращает правильное значение.
Что я делаю неправильно? Как получить правильный результат с сервера?
Ответы
Ответ 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);
});
}
}
}