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

时间:2022-09-17 02:16:53

I want to send a request to a server and process the returned value:

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

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

Am I using Task correctly? I don't think so because the Send() method returns string.Empty every time, while Print returns the correct value.

我使用任务正确吗?我不这么认为,因为Send()方法返回字符串。每次为空,而Print返回正确的值。

What am I doing wrong? How do I get the correct result from a server?

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

5 个解决方案

#1


21  

Your Print method likely needs to wait for the continuation to finish (ContinueWith returns a task which you can wait on). Otherwise the second ReadAsStringAsync finishes, the method returns (before result is assigned in the continuation). Same problem exists in your send method. Both need to wait on the continuation to consistently get the results you want. Similar to below

您的打印方法可能需要等待继续完成(ContinueWith返回一个您可以等待的任务)。否则,第二个ReadAsStringAsync结束,方法返回(在结果被分配到continuation之前)。发送方法中也存在同样的问题。两者都需要等待延续,才能始终得到您想要的结果。类似于下面

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


5  

It waits for client.GetAsync("aaaaa");, but doesn't wait for result = Print(x)

它等待client.GetAsync(“aaaaa”);,但不等待result = Print(x)

Try responseTask.ContinueWith(x => result = Print(x)).Wait()

responseTask试试。ContinueWith(x =>结果= 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");

Above code doesn't guarantee the output:

以上代码不保证输出:

In task
In ContinueWith
End

But this does (see the 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


0  

I'm an async novice, so I can't tell you definitively what is happening here. I suspect that there's a mismatch in the method execution expectations, even though you are using tasks internally in the methods. I think you'd get the results you are expecting if you changed Print to return a Task<string>:

我是一个异步新手,所以我不能肯定地告诉你这里发生了什么。我怀疑在方法执行期望中存在不匹配,即使您在方法内部使用任务。我认为,如果您更改了Print以返回一个任务 :

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

#4


0  

When working with continuations I find it useful to think of the place where I write .ContinueWith as the place from which execution immediately continues to the statements following it, not the statements 'inside' it. In that case it becomes clear that you would get an empty string returned in Send. If your only processing of the response is writing it to the console, you don't need any Wait in Ito's solution - the console printout will happen without waits but both Send and Print should return void in that case. Run this in console app and you will get printout of the page.

在使用continuations时,我觉得应该考虑我写的地方。继续作为执行的地方,它会立即继续执行下面的语句,而不是“内部”的语句。在这种情况下,很明显,您将在Send中返回一个空字符串。如果您对响应的唯一处理是将其写入控制台,则不需要在Ito的解决方案中等待——控制台打印将不需要等待,但在这种情况下,发送和打印都应该返回void。在控制台应用程序中运行它,您将得到打印输出页面。

IMO, waits and Task.Result calls (which block) are necessary sometimes, depending on your desired flow of control, but more often they are a sign that you don't really use asynchronous functionality correctly.

国际海事组织、等待和任务。结果调用(该块)有时是必要的,这取决于您想要的控制流,但是更多的情况是,它们是您没有正确地使用异步功能的标志。

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

#5


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

#1


21  

Your Print method likely needs to wait for the continuation to finish (ContinueWith returns a task which you can wait on). Otherwise the second ReadAsStringAsync finishes, the method returns (before result is assigned in the continuation). Same problem exists in your send method. Both need to wait on the continuation to consistently get the results you want. Similar to below

您的打印方法可能需要等待继续完成(ContinueWith返回一个您可以等待的任务)。否则,第二个ReadAsStringAsync结束,方法返回(在结果被分配到continuation之前)。发送方法中也存在同样的问题。两者都需要等待延续,才能始终得到您想要的结果。类似于下面

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


5  

It waits for client.GetAsync("aaaaa");, but doesn't wait for result = Print(x)

它等待client.GetAsync(“aaaaa”);,但不等待result = Print(x)

Try responseTask.ContinueWith(x => result = Print(x)).Wait()

responseTask试试。ContinueWith(x =>结果= 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");

Above code doesn't guarantee the output:

以上代码不保证输出:

In task
In ContinueWith
End

But this does (see the 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


0  

I'm an async novice, so I can't tell you definitively what is happening here. I suspect that there's a mismatch in the method execution expectations, even though you are using tasks internally in the methods. I think you'd get the results you are expecting if you changed Print to return a Task<string>:

我是一个异步新手,所以我不能肯定地告诉你这里发生了什么。我怀疑在方法执行期望中存在不匹配,即使您在方法内部使用任务。我认为,如果您更改了Print以返回一个任务 :

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

#4


0  

When working with continuations I find it useful to think of the place where I write .ContinueWith as the place from which execution immediately continues to the statements following it, not the statements 'inside' it. In that case it becomes clear that you would get an empty string returned in Send. If your only processing of the response is writing it to the console, you don't need any Wait in Ito's solution - the console printout will happen without waits but both Send and Print should return void in that case. Run this in console app and you will get printout of the page.

在使用continuations时,我觉得应该考虑我写的地方。继续作为执行的地方,它会立即继续执行下面的语句,而不是“内部”的语句。在这种情况下,很明显,您将在Send中返回一个空字符串。如果您对响应的唯一处理是将其写入控制台,则不需要在Ito的解决方案中等待——控制台打印将不需要等待,但在这种情况下,发送和打印都应该返回void。在控制台应用程序中运行它,您将得到打印输出页面。

IMO, waits and Task.Result calls (which block) are necessary sometimes, depending on your desired flow of control, but more often they are a sign that you don't really use asynchronous functionality correctly.

国际海事组织、等待和任务。结果调用(该块)有时是必要的,这取决于您想要的控制流,但是更多的情况是,它们是您没有正确地使用异步功能的标志。

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

#5


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