C#异步任务无限等待

12

我正在尝试使用“async”和“await”提供的功能来异步下载网页内容,但是遇到了任务无限等待完成的问题。请问以下代码片段有何问题?

protected void Page_Load(object sender, EventArgs e)
{
    var websites = new string[] {"http://www.cnn.com","http://www.foxnews.com"};
    var tasks = websites.Select(GenerateSomeContent).ToList();

    //I don't want to use 'await Tasks.WhenAll(tasks)' as I need to block the
    //page load until the all the webpage contents are downloaded
    Task.WhenAll(tasks).Wait();

    //This line is never hit on debugging
    var somevalue = "Complete";
}

static async Task<Results> GenerateSomeContent(string url)
{
    var client = new HttpClient();
    var response = await client.GetAsync(url); //Await for response
    var content = await response.Content.ReadAsStringAsync();
    var output = new Results {Content = content};
    return output;
}

//Sample class to hold results
public class Results
{
    public string Content;
}

1
可能是await vs Task.Wait - Deadlock?的重复问题 - 描述确切发生了什么 - awaitWait是非常不同的东西。 - Alexei Levenkov
在我的例子中,代码执行在“Task.WhenAll(tasks).Wait();”这一行停滞不前。 - infinity
2个回答

21

首先,请确保您正在使用的是.NET 4.5,而不是.NET 4.0。ASP.NET在.NET 4.5中变得“async”感知。

然后,正确的解决方案是等待“Task.WhenAll”的结果:await

var tasks = websites.Select(GenerateSomeContent);
await Task.WhenAll(tasks);

ASP.NET管道(仅在.NET 4.5中)将检测到您的代码正在使用await,并将暂停该请求,直到Page_Load完成运行。

在这种情况下同步阻塞任务使用Wait会导致死锁,如我在博客中所解释的那样


在你的博客文章中,你说要在整个堆栈中使用async/await...如果这不是一个选项...你如何正确地使用.Wait() - Leonardo
@Leonardo:没有一种适用于所有情况的解决方案,但我在MSDN关于棕地异步的文章中列举了几个技巧。 - Stephen Cleary

1

+1 Stephen Cleary. 刚刚了解到您需要在Page_Load前使用async关键字,如下所示:

protected async void Page_Load(object sender, EventArgs e)
{
   var tasks = websites.Select(GenerateSomeContent);
   await Task.WhenAll(tasks);
}

在您的代码后台文件中(如果是asp.net web form应用程序),还应该具有Async="true"属性。
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="default.aspx.cs" Async="true" Inherits="EmptyWebForm._default" %>

希望这对访客有所帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接