You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity中DownloadScreenshotFromStorageAsync函数线程阻塞及TaskCanceledException问题排查

解决Unity Firebase存储下载异步函数阻塞/死锁问题

看起来你遇到了Unity中Firebase Storage异步下载的典型死锁和异常处理问题,我来帮你拆解并修复这个函数:

核心问题分析

  • 死锁根源:Unity的await默认会捕获主线程同步上下文,当Firebase后台任务完成后试图切回主线程时,如果主线程被其他同步操作占用(比如UI阻塞、同步锁等),就会触发死锁。
  • TaskCanceledException:大概率是因为下载任务超时或被意外取消,但你的函数没有处理这类异常,也没有设置合理的超时机制。
  • 失败时未返回null:当前代码缺少全局异常捕获,无法保证所有失败场景都返回null。

修复后的完整代码

public async Task<Texture2D> DownloadScreenshotFromStorageAsync(string url)
{
    try
    {
        Debug.Log("Downloading from Storage...\n" + url);
        
        // 获取Firebase存储引用(补全你的初始化代码)
        var cloud = _firebaseStorage.GetReferenceFromUrl(url);
        
        // 限制下载的图片大小为5MB,可根据需求调整
        var dlScreenshot_task = cloud.GetBytesAsync(1024 * 1024 * 5);
        // 用Task.WhenAny实现超时机制,避免无限阻塞(这里设为10秒)
        var completedTask = await Task.WhenAny(dlScreenshot_task, Task.Delay(TimeSpan.FromSeconds(10)));
        
        if (completedTask != dlScreenshot_task)
        {
            Debug.LogWarning("Download timed out for URL: " + url);
            return null;
        }
        
        // 检查下载任务是否成功完成
        if (!dlScreenshot_task.IsCompletedSuccessfully)
        {
            Debug.LogError("Download failed with error: " + dlScreenshot_task.Exception?.Message);
            return null;
        }
        
        byte[] screenshotBytes = dlScreenshot_task.Result;
        
        // 纹理操作需在主线程执行,这里直接创建加载即可
        Texture2D texture = new Texture2D(2, 2);
        if (texture.LoadImage(screenshotBytes))
        {
            return texture;
        }
        else
        {
            Debug.LogError("Failed to load image bytes into Texture2D");
            UnityEngine.Object.Destroy(texture);
            return null;
        }
    }
    catch (Exception ex)
    {
        // 捕获所有异常(包括TaskCanceledException、网络错误等)
        Debug.LogError("Unexpected error during download: " + ex.Message);
        return null;
    }
}

关键修复点说明

  • 超时机制:通过Task.WhenAny同时等待下载任务和延迟任务,防止任务无限阻塞,超时直接返回null。
  • 全局异常捕获:整个逻辑包裹在try-catch中,确保任何异常场景都能返回null,符合你的需求。
  • 纹理加载安全:创建Texture后如果加载失败,及时销毁对象避免内存泄漏。
  • 避免死锁:通过Task.WhenAny绕开强制切回主线程的逻辑,同时确保纹理操作在Unity允许的主线程执行。

额外注意事项

  • 确保_firebaseStorage已经在Start或Awake中完成初始化,避免空引用错误。
  • 如果你的图片尺寸较大,调整GetBytesAsync的大小限制参数。
  • 若需要在后台线程处理字节数据,可单独拆分逻辑,但纹理创建必须回到主线程。

内容的提问来源于stack exchange,提问作者Jimmy Alger

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 04:23:08