簡體   English   中英

Unity C# - 在協程中執行異步任務並等待它完成

[英]Unity C# - Execute async task within a Coroutine and wait for it to finish

我對 Unity 開發完全陌生,我正在嘗試將異步功能集成到現有的 Coroutine 中,但到目前為止我遇到了幾個問題。 我的問題:

  1. Unity 應用程序完全凍結,可能是因為它被線程阻塞了。 我在傳統的 C#(控制台應用程序)中實現了這段代碼,沒有任何問題。(經過一些修改,現在在 Unity 中修復)
  2. 下載任務開始但從未完成。 僅當我將其作為 APK 運行時才會發生這種情況。 在 PC 上的 Unity 調試工作正常。

我的代碼:

public void Validate()
{
     StartCoroutine(DoWork());
}


 private IEnumerator DoWork()
 {
    bool success;
    //Perform some calculations here
    ..
    ..
    success = true;
    //
    yield return new WaitForSeconds(3);
    if(success){
        GetInfo(_files);
    }
 
 }
 
 async void GetInfo(List<string> files)
 {
     await StartDownload(files);
     
     //After completing the download operation, perform some other actions in the background
     ...
     ...
     //
     
     //When done, change the active status of specific game objects
 }
 
 
 public async Task StartDownload(List<string> files){
    
    var t1 = GetFileSizesAsync(files);
    var t2 = DownloadFilesAsync(files);
    
    await Task.WhenAll(t1, t2);
 
 }
 
  public async Task GetFileSizesAsync(List<string> urls)
  {
        foreach (var url in urls)
           GetFileSize(url);
           
        txtSize.text = totalSizeMb +"MB";
  }
  
   private void GetFileSize(string url)
   {
         var uri = new Uri(url);
        var webRequest = HttpWebRequest.Create(uri);
        webRequest.Method = "GET";
        try
        {
            var webResponse = webRequest.GetResponse();
            var fileSize = webResponse.Headers.Get("Content-Length");
            var fileSizeInMegaByte = Math.Round(Convert.ToDouble(fileSize) / 1024.0 / 1024.0, 2);
            totalSizeMb = totalSizeMb + fileSizeInMegaByte;
          
        }
        catch (Exception ex)
        {

        }
        finally
        {
            webRequest.Abort();
        }
   }
   
   
   public async Task<List<string>> DownloadFilesAsync(List<string> urls)
    {
        var result = new List<string>();
        
        foreach (var url in urls)
           var download = await DownloadFile(url);
            if(download)
                result.Add(url);
            
        return response;
    }
    
    private async Task<bool> DownloadFile(string url)
    {
        WebClient webClient = new WebClient();
        var uri = new Uri(url);
        var saveHere = "C:\\...";
        try
        {
            await webClient.DownloadFileTaskAsync(uri, saveHere);
            return true;
        }
        catch (Exception ex)
        {
            return false;
        }
    }

你能告訴我我在這里做錯了什么嗎? 我嘗試了幾種方法,但無法找到合適的解決方案。

謝謝!

我寧願做到

async Task GetInfo(List<string> files){ ... }

然后在你的協程中做

var t = Task.Run(async () => await GetInfo(files));

while(!t.IsCompleted)
{
    yield return null;
}

// Or also
//yield return new WaitUntil(() => t.IsCompleted);

if(!t.IsCompletedSuccesfully)
{
    Debug.LogError("Task failed or canceled!");
    yield break;
}

但請注意:

完成后,更改特定游戲對象的活動狀態

這不能異步完成! 它必須發生在 Unity 主線程中! 因此,您可能寧願從GetInfo任務中返回一些內容,並在完成后激活 Coroutine 中的對象。

在循環並產生之后,您可以通過以下方式訪問返回值

var result = t.Result;

首先。 凍結肯定是由 IEneumerator 完成的,因為我沒有看到產量聲明。 什么是收益聲明? 呃……谷歌一下。 勒爾

其次。 普通的空洞不是很好嗎?

第三。 我對異步不太了解,因為我對它們很陌生,但我相當肯定你不需要它們:

任務 GetFileSizesAsync(列出 url)

異步任務<List> DownloadFilesAsync(List urls)

我可能錯了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM