Task.WhenAny 的陷阱

最近做的一个下载程序经常会陷入死循环,一直下载,未报异常,但就是下载的文件不存在。

public async Task<bool> DownloadFileTimeout(string fileUrl, string savePath)
{
    var timeoutTask = Task.Delay(this.Timeout);

    // 调用下载文件的异步方法
    var downloadTask = DownloadFileTaskAsync(fileUrl, savePath);

    // 等待第一个完成的任务(下载或超时)
    var completedTask = await Task.WhenAny(downloadTask, timeoutTask);

    if (completedTask == downloadTask)
    {
       return true;
    }
    else
    {
        return false;
    }
}
public async Task DownloadFileTaskAsync(string fileUrl, string savePath)
{
    // 发送 GET 请求
    HttpResponseMessage response = await this.GetAsync(fileUrl, HttpCompletionOption.ResponseHeadersRead);

    // 确保请求成功
    response.EnsureSuccessStatusCode();

    // 获取文件流
    using (var stream = await response.Content.ReadAsStreamAsync())
    {
        // 创建文件流用于保存文件
        using (var fileStream = new FileStream(savePath, FileMode.Create, FileAccess.Write, FileShare.None))
        {
            // 将内容写入文件
            await stream.CopyToAsync(fileStream);
        }
    }
}

DeepSeek 分析如下:

原因解释:‌

‌Task.WhenAny 的陷阱‌
即使 downloadTask 因异常而失败,它仍会先于 timeoutTask 完成,导致 completedTask == downloadTask 为 true。但此时 downloadTask 可能处于 ‌Faulted‌ 状态。

‌检查任务的实际结果‌
通过 await downloadTask 重新抛出潜在异常,并用 try/catch 捕获。若下载成功(无异常),返回 true;若抛出异常(如 HTTP 错误),返回 false。

‌正确处理超时与错误‌
确保只有下载‌真正成功‌时返回 true,其他情况(超时或 HTTP 错误)均返回 false

修改后代码如下:

public async Task<bool> DownloadFileTimeout(string fileUrl, string savePath)
{
    var timeoutTask = Task.Delay(this.Timeout);
    var downloadTask = DownloadFileTaskAsync(fileUrl, savePath);
    var completedTask = await Task.WhenAny(downloadTask, timeoutTask);

    if (completedTask == downloadTask)
    {
        try
        {
            await downloadTask; // 触发可能的异常
            return true;
        }
        catch
        {
            return false; // 下载失败时返回 false
        }
    }
    else
    {
        return false; // 超时返回 false
    }
}

也就是说异步方法,很多异常并不能总是在其调用链父级被捕获到。如果想抛出异常,还得自己接力。

 

posted on 2025-03-23 09:12  空明流光  阅读(19)  评论(0)    收藏  举报

导航