我如何等待任务在C#中完成?

时间:2012-11-03 16:56:31

标签: c# .net task task-parallel-library wait

我想向服务器发送请求并处理返回的值:

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会返回正确的值。

我做错了什么?如何从服务器获得正确的结果?

6 个答案:

答案 0 :(得分:29)

您的Print方法可能需要等待延续完成(ContinueWith返回您可以等待的任务)。否则,第二个ReadAsStringAsync结束,该方法返回(在继续中分配结果之前)。您的send方法中存在同样的问题。两者都需要等待继续以始终如一地获得您想要的结果。类似于下面的

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

答案 1 :(得分:6)

等待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");

答案 2 :(得分:0)

我是一个异步的新手,所以我无法明确地告诉你这里发生了什么。我怀疑方法执行期望存在不匹配,即使您在方法内部使用任务。如果您更改了Print以返回任务&lt; string&gt;我认为您将得到您期望的结果:

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

答案 3 :(得分:0)

当使用continuation时,我发现想到我写的地方很有用.ContinueWith作为执行立即继续执行它后面的语句的地方,而不是语句'inside'。在这种情况下,很明显你会在Send中返回一个空字符串。如果您对响应的唯一处理是将其写入控制台,则不需要任何Wait in Ito的解决方案 - 控制台打印输出将无需等待,但在这种情况下,发送和打印都应返回无效。在控制台应用程序中运行此命令,您将获得该页面的打印输出。

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

答案 4 :(得分:0)

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

答案 5 :(得分:0)

一个简单的示例,回答标题

string output = "Error";
Task task = Task.Factory.StartNew(() =>
{
    System.Threading.Thread.Sleep(2000);
    output = "Complete";
});

task.Wait();
Console.WriteLine(output);