TaskCanceledException线程阻塞

时间:2018-04-15 23:02:20

标签: c# firebase asynchronous async-await race-condition

以下函数偶尔会起作用,但大多数时候会阻塞await dlScreenshot_task处的线程。

Debug.Log("Downloading from Storage...\n" + url);触发每个图片网址,然后Unity死锁。偶尔它会抛出一个TaskCanceledException。如果任务以任何方式失败,则return null应该Task

public async Task<Texture2D> DownloadScreenshotFromStorageAsync(string url)
{
    byte[] screenshotBytes;
    //Firebase.Storage
    StorageReference cloud = _firebaseStorage.GetReferenceFromUrl(_storageBucketURL + url);
    if( cloud != null ) {
        Task<byte[]> dlScreenshot_task = cloud.GetBytesAsync(1920 * 1080);
        Debug.Log("Downloading from Storage...\n" + url);

        try {    
            screenshotBytes = await dlScreenshot_task;

            if( screenshotBytes != null ) {
                Debug.Log("DLed: " + url);
                return MetaLoader.DeserializeImage(screenshotBytes);
            }
            else {
                return null;
            }
        }
        catch(AggregateException aex ) {
            StorageException store_ex = aex.InnerException as StorageException;
            if(store_ex != null ) { Debug.Log("Storage Exception " + store_ex.ErrorCode); }
            return null;
        }
        catch(TaskCanceledException t ) {
            Debug.LogWarning(t);
            return null;
        }
    }
    else {
        Debug.Log("Cloud Storage Reference failed for " + _storageBucketURL + url);
        return null;
    }
}  

调用函数,使用MSDN Docs regarding Task-based async programming中的交错:

private async void DisplayScreenshotsFromDB()
{
    Task<List<string>> dl_task = DownloadURLsAsync();

    List<string> screenshotURLs = await dl_task;

    //Interleaved image downloading
    //https://docs.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/consuming-the-task-based-asynchronous-pattern
    List<Task<Texture2D>> imageTasks =
                    (from imageUrl in screenshotURLs select DownloadScreenshotFromStorageAsync(imageUrl)).ToList();
    while( imageTasks.Count > 0 ) {
        Task<Texture2D> imageTask = await Task.WhenAny(imageTasks);
        try {
            imageTasks.Remove(imageTask);

            Texture2D image = await imageTask;
            DisplayScreenshot(image);
        }
        catch (Exception e) {
            imageTasks.Remove(imageTask);
            Debug.Log("Download failed\n" + e);
        }
    }
}

我是否创造了一种我没有看到的竞争条件? 或者为什么抓住TaskCanceledException会阻止其他任务完成?
(它应该是可恢复的例外, return null 是可以接受的。)

值得注意的是,我不相信问题在于交错,调用功能。如果调用函数的结构如下,则会出现同样的问题:

Task<List<string>> dl_task = DownloadURLsAsync();

List<string> screenshotURLs = await dl_task;
foreach(string s in screenshotURLs ) {
    await DownloadScreenshotAsync(s);
}

0 个答案:

没有答案