wait WebClient.DownloadStringTaskAsync将永远等待,但访问Result属性可以工作

本文关键字:属性 Result 工作 访问 DownloadStringTaskAsync WebClient 永远等待 wait | 更新日期: 2023-09-27 18:27:46

以下代码运行良好(在控制台上打印标记):

System.Net.WebClient wc = new System.Net.WebClient();
var task1 = wc.DownloadStringTaskAsync("https://www.google.com.au");
Console.WriteLine(task1.Result); // works

但当我等待任务时,它只是永远等待,任务的状态是等待激活:

System.Net.WebClient wc = new System.Net.WebClient();
var task1 = wc.DownloadStringTaskAsync("https://www.google.com.au");
Console.WriteLine(await task1);
Console.WriteLine("done!"); // this never gets printed

我错过了什么?

编辑:完整代码:

static void Main(string[] args)
{
    DoIt(); 
}
static async void DoIt()
{
    System.Net.WebClient wc = new System.Net.WebClient();
    var task1 = wc.DownloadStringTaskAsync("https://www.google.com.au");
    Console.WriteLine(await task1);
    Console.WriteLine("done!"); // this never gets printed
}

wait WebClient.DownloadStringTaskAsync将永远等待,但访问Result属性可以工作

我错过了什么?

目前,根据您调用代码的方式,我看不出该任务是如何WaitingForActivation的。一旦DoIt命中第一个await,它就会将控制权交还给调用者,这就是您的Main方法,它应该终止并关闭您的控制台。

使用Task.Result之所以有效,是因为它在异步方法上同步阻塞,因此它等待它完成,然后您可以看到打印到控制台的结果。

实际上,您需要做的是使DoIt成为async Task而不是async void,并在那里使用Task.Wait来同步阻止,这样Main就不会终止:

static void Main(string[] args)
{
    DoItAsync().Wait(); 
}
static async Task DoItAsync()
{
    System.Net.WebClient wc = new System.Net.WebClient();
    var task1 = wc.DownloadStringTaskAsync("https://www.google.com.au");
    Console.WriteLine(await task1);
    Console.WriteLine("done!"); // this never gets printed
}

注意使用Task.ResultTask.Wait只是为了使控制台不终止。在任何其他环境(基于UI或ASP.NET)中,都不应该阻塞异步代码,而应该始终对异步方法执行await

您不是在awaitWait()中使用DoIt()方法,即async。由于Main()不能成为async,您唯一的选择是同步等待任务完成。

此外,awaitWait()异步方法不可能返回void,因此我们必须使其返回Task(或Task<T>,如果方法必须返回一些值)。返回void的异步方法的调用方无法知道它何时返回,也无法知道它是否抛出任何异常。

using System;
using System.Threading.Tasks;
public class Program
{
    public static void Main()
    {
        Program.DoIt().Wait();
    }
    private static async Task DoIt()
    {
        System.Net.WebClient wc = new System.Net.WebClient();
        var task1 = wc.DownloadStringTaskAsync("https://www.google.com.au");
        Console.WriteLine(await task1);
        Console.WriteLine("done!"); 
    }
}