不等待时TaskCanceledException

每当我同步返回另一个任务而不是等待它时,我似乎得到一个TaskCanceledException ,遵循最后等待时的指导原则。

TaskCanceledException代码

 public static class Download { public static Task FromYouTubeAsync(string videoUri) { using (var client = new HttpClient()) { return FromYouTubeAsync( () => client .GetStringAsync(videoUri), uri => client .GetByteArrayAsync(uri)); } } public async static Task FromYouTubeAsync( Func<Task> sourceFactory, Func<string, Task> downloadFactory) { string source = await // TaskCanceledException here sourceFactory() .ConfigureAwait(false); // find links return await downloadFactory(links.First()) .ConfigureAwait(false); } } 

无exception代码

这里,方法签名的第一个重载更改为async,它等待第二个重载。 出于某种原因,这可以防止TaskCanceledException

 public static class Download { public async static Task FromYouTubeAsync(string videoUri) { using (var client = new HttpClient()) { return await FromYouTubeAsync( () => client .GetStringAsync(videoUri), uri => client .GetByteArrayAsync(uri)); } } public async static Task FromYouTubeAsync( Func<Task> sourceFactory, Func<string, Task> downloadFactory) { string source = await // No exception! sourceFactory() .ConfigureAwait(false); // find links return await downloadFactory(links.First()) .ConfigureAwait(false); } } 

为什么会发生这种情况,我该怎么做才能解决它( 除了等待上面链接中描述的浪费资源的方法)?

抱歉, 您发布的链接是关于应用优化的只有在方法await之后该方法await时才适用 。 引用post:

然而,在这种情况下,我们正在处理一个任务来表示方法中的最后一个语句,因此它实际上已经表示了整个方法的处理…

在您的示例中,该任务不代表方法中的最后一个语句。 再看一遍:

 public async static Task FromYouTubeAsync(string videoUri) { using (var client = new HttpClient()) { return await FromYouTubeAsync(...); } } 

await 之后发生了一些事情:特别是处理client 。 因此,该博客文章提到的优化不适用于此处

这就是您尝试直接返回任务时看到exception的原因:

 public static Task FromYouTubeAsync(string videoUri) { using (var client = new HttpClient()) { return FromYouTubeAsync(...); } } 

此代码开始下载, 然后处理HttpClient ,然后返回任务。 HttpClient将在处置时取消任何未完成的操作。

使用await的代码将(异步)等待HTTP操作在它处理HttpClient之前完成。 这就是你需要的行为, await是表达它的最干净的方式。 在这种情况下,它根本不是“浪费资源”,因为在下载完成之前,您必须推迟处置。