不等待时出现 TaskCanceledException

TaskCanceledException when not awaiting

每当我同步 return 另一个任务而不是等待它时,我似乎都会收到 TaskCanceledException,遵循 When at last you await 中的指导方针。

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);
    }
}

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

抱歉,link you posted 是关于应用优化仅当方法在其 await[ 之后不执行任何操作时才适用=41=]。引用 post:

In this case, however, we’re being handed a task to represent the last statement in the method, and thus it’s in effect already a representation of the entire method’s processing...

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

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

await 之后发生了一些事情:特别是 client 的处置。所以那个博客里提到的优化post在这里不适用.

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

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

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

使用 await 的代码将(异步地)等待 HTTP 操作完成,然后再处理 HttpClient。这就是您需要的行为,而 await 是最简洁的表达方式。在这种情况下,它根本不是 "waste of resources",因为您 必须 将处理推迟到下载完成后。