如何在 C# 中等到 Task 完成?
Posted
技术标签:
【中文标题】如何在 C# 中等到 Task 完成?【英文标题】:How do I wait until Task is finished in C#? 【发布时间】:2012-10-24 01:30:11 【问题描述】:我想向服务器发送请求并处理返回值:
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】:回答标题的简洁示例
string output = "Error";
Task task = Task.Factory.StartNew(() =>
System.Threading.Thread.Sleep(2000);
output = "Complete";
);
task.Wait();
Console.WriteLine(output);
【讨论】:
谢谢,这帮助我找到了解决方案。【参考方案2】: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;
【讨论】:
【参考方案3】:在处理延续时,我发现将我编写 .ContinueWith 的位置视为立即继续执行到它后面的语句的地方很有用,而不是它“内部”的语句。在这种情况下,很明显您将在 Send 中返回一个空字符串。如果您对响应的唯一处理是将其写入控制台,则在 Ito 的解决方案中不需要任何等待 - 控制台打印输出无需等待即可发生,但在这种情况下,发送和打印都应返回 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);
);
【讨论】:
不是控制台应用程序? Readline 不可用,有什么解决办法吗?【参考方案4】:它等待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.Wait()。 当您调用task.Wait()
时,您等待的是原始Task
,而不是您使用ContinueWith
创建的那个
你为什么不在newTask.Task()
之前打电话给responseTask.Wait()
?
@OskarK.,无需等待上一个任务。 ContinueWith
将保证之前的任务完成。【参考方案5】:
您的 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;
【讨论】:
顺便说一句,调用异步然后立即等待它的模式与同步调用几乎相同。 当您被 .net Framework 4.0 卡住并且您在添加 microsoft.bcl.async nuget pkg 以使用 Await 时遇到问题时,这是最好的解决方案。【参考方案6】:我是异步新手,所以我无法确切地告诉你这里发生了什么。我怀疑方法执行期望不匹配,即使您在方法内部使用任务。如果您将 Print 更改为返回 Task
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;
【讨论】:
以上是关于如何在 C# 中等到 Task 完成?的主要内容,如果未能解决你的问题,请参考以下文章