DownloadStringTaskAsync和DownloadStringAsync之间的区别

6

我正在开发一款asp.net mvc5 web应用程序,但我不确定使用 DownloadStringTaskAsync() 和使用 DownloadStringAsync() 的区别。例如,如果我有以下webclient:

 using (WebClient wc = new WebClient())
 {
     string url = currentURL + "home/scanserver?tokenfromtms=" + "12345" + "&FQDN=allscan" ;
     var json = await wc.DownloadStringTaskAsync(url);
     TempData["messagePartial"] = string.Format("Scan has been completed. Scan reported generated");                 
 }

如果我将 DownloadStringTaskAsync(url) 更改为 DownloadStringAsync(url),是否会有任何差异?
2个回答

12

WebClient.DownloadStringAsync使用较旧的事件驱动异步模式 (EAP)

WebClient.DownloadStringTaskAsync使用较新的任务驱动异步模式 (TAP)

由于您的代码已经使用了async/await,我建议您坚持使用TAP方法。TAP代码比EAP代码更易维护。

您还可以更进一步地考虑使用HttpClient代替WebClientWebClient中的奇怪命名是因为它支持同步和EAP,然后更新以包括TAP。相比之下,HttpClient是一种基于TAP的较新类型,因此其API更干净。


是的,这就是异步工作的方式。我鼓励你查看我写的文章,它提供了异步工作的一般概述,并揭示了许多人认为它会做但实际上并不会做的一些神话。http://cpratt.co/async-not-faster/ - Chris Pratt
2
@johnG:await会暂停当前方法,直到字符串下载完成。EAP版本(DownloadStringAsync)无法使用await,因此在下载过程中,您的方法将立即继续执行,而Web客户端通过DownloadStringCompleted通知您下载完成。请注意,与事件处理代码相比,await代码更易于编写和维护。 - Stephen Cleary
@Stephen Cleary 这是非常重要的注释,因为在另一个回复中他们提到两者都会等待字符串下载完成... - John John
1
@johnG:我不确定为什么提示没有出现。你确实应该在DownloadStringTaskAsync中使用await,所以我希望VS能够识别出来... - Stephen Cleary
2
@johnG:你可以将EAP成员包装在TAP包装器中,并等待该任务。但这是没有意义的,因为DownloadStringTaskAsync已经这样做了。 - Stephen Cleary
显示剩余3条评论

5
DownloadStringTaskAsyncDownloadStringAsync文档非常好地展示了它们的相似之处和不同之处。
它们都是非阻塞的异步方法。但是,DownloadStringAsync的返回类型为 void,需要通过监听 DownloadStringCompleted事件来获取 Result 中的结果,而DownloadStringTaskAsync方法返回一个Task<string>
后者在您需要等待并行异步操作以继续执行或如果您想要在操作完成后调用ContinueWith时非常有用。此外,使用后一种方法,您还需要在任务处于已完成状态时从该任务检索结果,这可以通过 await 解开该任务来实现。
最后,DownloadStringAsync需要一个 URI,而DownloadStringTaskAsync将接受一个字符串。
为了方便使用,只需将DownloadStringTaskAsync放置在异步方法中即可。
void Main()
{
    using (WebClient wc = new WebClient())
    {
        var json = GetGoogleFromTask(wc);                
        json.Dump();
    }
}

public async Task<string> GetGoogleFromTask(WebClient wc)
{
    string url = "http://www.google.com" ;
    var json = await wc.DownloadStringTaskAsync(url);
    return json;
}

或者,您也可以仅返回任务,以便您可以继续其他操作,而不需要等待异步方法返回:

void Main()
{
    using (WebClient wc = new WebClient())
    {
        var json = GetGoogleFromTask(wc);                
        json.Dump();
    }
}

public Task<string> GetGoogleFromTask(WebClient wc)
{
    string url = "http://www.google.com" ;
    var json = wc.DownloadStringTaskAsync(url);
    return json;
}

@johnG 我已经澄清了我的答案,因为DownloadStringAsync的行为并不完全符合我的预期。我还添加了如何使用DownloadStringTaskAsync的示例。 - David L
2
简单来说,每当您看到方法的 *Async*TaskAsync 版本时,这意味着 *Async 版本早于在 C# 中引入 async-await,并使用事件模式实现类似的效果。*TaskAsync 方法是在 async-await 之后添加的,并利用了 async-await。前面的方法仍然保持向后兼容性。 - Chris Pratt
@ChrisPratt 所以我不必在使用 DownloadStringTaskAsync 时显式地编写 "await" 是为什么?如果我明确编写 "await",它会有任何区别吗? - John John
1
你永远不需要使用 await。有时候你实际上可能想要与 Task<T> 对象进行交互。await 关键字只是一种语法糖,它会自动展开任务响应。在功能上,它与仅执行 MyAsyncTask().Result 相同(尽管有一些异常处理被卷入其中,而你无法只是访问 Result 属性)。 - Chris Pratt
@johnG Chris的观点是你不必强制使用await,这就是我在第二个例子中所指出的。你实际上可以返回任务并从中检索.Result属性。await只是语法糖。 - David L
显示剩余3条评论

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