【问题标题】:TaskCanceledException when not awaiting未等待时的 TaskCanceledException
【发布时间】:2015-09-20 15:01:30
【问题描述】:

按照When at last you await 中的指南,每当我同步返回另一个任务而不是等待它时,我似乎都会收到TaskCanceledException

TaskCanceledException 代码

public static class Download
{
    public static Task<byte[]> FromYouTubeAsync(string videoUri)
    {
        using (var client = new HttpClient())
        {
            return FromYouTubeAsync(
                () => client
                .GetStringAsync(videoUri),
                uri => client
                .GetByteArrayAsync(uri));
        }
    }

    public async static Task<byte[]> FromYouTubeAsync(
        Func<Task<string>> sourceFactory, Func<string, Task<byte[]>> downloadFactory)
    {
        string source = await // TaskCanceledException here
            sourceFactory()
            .ConfigureAwait(false);

        // find links

        return await
            downloadFactory(links.First())
            .ConfigureAwait(false);
    }
}

无异常代码

这里,方法签名的第一个重载被更改为异步,它等待第二个重载。出于某种原因,这会阻止TaskCanceledException

public static class Download
{
    public async static Task<byte[]> FromYouTubeAsync(string videoUri)
    {
        using (var client = new HttpClient())
        {
            return await FromYouTubeAsync(
                () => client
                .GetStringAsync(videoUri),
                uri => client
                .GetByteArrayAsync(uri));
        }
    }

    public async static Task<byte[]> FromYouTubeAsync(
        Func<Task<string>> sourceFactory, Func<string, Task<byte[]>> downloadFactory)
    {
        string source = await // No exception!
            sourceFactory()
            .ConfigureAwait(false);

        // find links

        return await
            downloadFactory(links.First())
            .ConfigureAwait(false);
    }
}

为什么会发生这种情况,我可以做些什么来解决它(除了等待方法,这会浪费资源,如上面链接中所述)?

【问题讨论】:

    标签: c# asynchronous async-await task


    【解决方案1】:

    抱歉,link you posted 是关于应用优化仅当该方法在其await 之后没有执行任何操作时才适用。引用帖子:

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

    在您的示例中,任务确实代表方法中的最后一条语句。再看一遍:

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

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

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

    public static Task<byte[]> FromYouTubeAsync(string videoUri)
    {
      using (var client = new HttpClient())
      {
        return FromYouTubeAsync(...);
      }
    }
    

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

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

    【讨论】:

    • 很好的解释。我想知道HttpClient 是否应该抛出ObjectDisposedException,因为模糊的错误消息只是令人困惑。感谢您的帮助!
    猜你喜欢
    • 2016-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-11
    • 1970-01-01
    • 2019-10-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多