[英]How do I wait until Task is finished in C#?
我想向服務器發送請求並處理返回值:
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
返回正確的值。
我究竟做錯了什么? 如何從服務器獲得正確的結果?
您的 Print 方法可能需要等待繼續完成(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;
}
它等待client.GetAsync("aaaaa");
, 但不等待result = Print(x)
嘗試responseTask.ContinueWith(x => result = Print(x)).Wait()
- 編輯 -
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");
我是一個異步新手,所以我不能確切地告訴你這里發生了什么。 我懷疑方法執行預期不匹配,即使您在方法內部使用任務。 我認為如果您將 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'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;
}
在處理延續時,我發現將我編寫 .ContinueWith 的位置視為執行立即繼續到它后面的語句的地方,而不是它“內部”的語句是很有用的。 在這種情況下,很明顯您將在 Send 中得到一個空字符串。 如果您對響應的唯一處理是將其寫入控制台,則在 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);
});
}
}
}
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;
}
回答標題的干凈示例
string output = "Error";
Task task = Task.Factory.StartNew(() =>
{
System.Threading.Thread.Sleep(2000);
output = "Complete";
});
task.Wait();
Console.WriteLine(output);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.