await WebClient.DownloadStringTaskAsync 永远等待,但访问 Result 属性 有效
await WebClient.DownloadStringTaskAsync waits forever but accessing Result property works
以下代码段工作正常(在控制台上打印标记):
System.Net.WebClient wc = new System.Net.WebClient();
var task1 = wc.DownloadStringTaskAsync("https://www.google.com.au");
Console.WriteLine(task1.Result); // works
但是当我等待任务时它只是永远等待并且任务的状态是 WaitingForActivation:
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
}
What am I missing?
目前,根据您调用代码的方式,我看不出任务是怎样的 WaitingForActivation
。一旦 DoIt
命中第一个 await
,它就会将控制权交还给调用者,这是您的 Main
方法,它应该终止并关闭您的控制台。
使用 Task.Result
之所以有效,是因为它会同步阻塞异步方法,因此它会等待它完成,然后您会看到结果打印到控制台。
你真正需要做的是用 DoIt
async Task
代替 async void
,并在那里使用 Task.Wait
同步阻塞,所以 Main
不会' t 终止:
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.Result
和 Task.Wait
只是为了让控制台不终止。在任何其他环境中(基于 UI 或 ASP.NET),您永远不应阻塞异步代码,而应始终 await
异步方法。
您没有 await
-ing 或 Wait()
-ing 您的 DoIt()
方法,即 async
。由于无法使 Main()
变为 async
,您唯一的选择是同步等待任务完成。
此外,await
或 Wait()
异步方法 returns void
是不可能的,因此我们必须使其成为 return Task
(或 Task<T>
,如果方法必须 return 某个值)。 returns void
异步方法的调用者无法知道它何时 returns 以及它是否抛出任何异常。
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!");
}
}
以下代码段工作正常(在控制台上打印标记):
System.Net.WebClient wc = new System.Net.WebClient();
var task1 = wc.DownloadStringTaskAsync("https://www.google.com.au");
Console.WriteLine(task1.Result); // works
但是当我等待任务时它只是永远等待并且任务的状态是 WaitingForActivation:
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
}
What am I missing?
目前,根据您调用代码的方式,我看不出任务是怎样的 WaitingForActivation
。一旦 DoIt
命中第一个 await
,它就会将控制权交还给调用者,这是您的 Main
方法,它应该终止并关闭您的控制台。
使用 Task.Result
之所以有效,是因为它会同步阻塞异步方法,因此它会等待它完成,然后您会看到结果打印到控制台。
你真正需要做的是用 DoIt
async Task
代替 async void
,并在那里使用 Task.Wait
同步阻塞,所以 Main
不会' t 终止:
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.Result
和 Task.Wait
只是为了让控制台不终止。在任何其他环境中(基于 UI 或 ASP.NET),您永远不应阻塞异步代码,而应始终 await
异步方法。
您没有 await
-ing 或 Wait()
-ing 您的 DoIt()
方法,即 async
。由于无法使 Main()
变为 async
,您唯一的选择是同步等待任务完成。
此外,await
或 Wait()
异步方法 returns void
是不可能的,因此我们必须使其成为 return Task
(或 Task<T>
,如果方法必须 return 某个值)。 returns void
异步方法的调用者无法知道它何时 returns 以及它是否抛出任何异常。
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!");
}
}