2016-05-16 43 views
3

我的目標是從亞馬遜網絡服務存儲桶下載圖像。C#Task.WaitAll未在等待

我有以下的代碼功能,一次下載多張圖片:

public static void DownloadFilesFromAWS(string bucketName, List<string> imageNames) 
{ 
    int batchSize = 50; 
    int maxDownloadMilliseconds = 10000; 

    List<Task> tasks = new List<Task>(); 

    for (int i = 0; i < imageNames.Count; i++) 
    { 
     string imageName = imageNames[i]; 
     Task task = Task.Run(() => GetFile(bucketName, imageName)); 
     tasks.Add(task); 
     if (tasks.Count > 0 && tasks.Count % batchSize == 0) 
     { 
      Task.WaitAll(tasks.ToArray(), maxDownloadMilliseconds);//wait to download 
      tasks.Clear(); 
     } 
    } 

    //if there are any left, wait for them 
    Task.WaitAll(tasks.ToArray(), maxDownloadMilliseconds); 
} 

private static void GetFile(string bucketName, string filename) 
{ 
    try 
    { 
     using (AmazonS3Client awsClient = new AmazonS3Client(Amazon.RegionEndpoint.EUWest1)) 
     { 
      string key = Path.GetFileName(filename); 

      GetObjectRequest getObjectRequest = new GetObjectRequest() { 
       BucketName = bucketName, 
        Key = key 
      }; 

      using (GetObjectResponse response = awsClient.GetObject(getObjectRequest)) 
      { 
       string directory = Path.GetDirectoryName(filename); 
       if (!Directory.Exists(directory)) 
       { 
        Directory.CreateDirectory(directory); 
       } 

       if (!File.Exists(filename)) 
       { 
        response.WriteResponseStreamToFile(filename); 
       } 
      } 
     } 
    } 
    catch (AmazonS3Exception amazonS3Exception) 
    { 
     if (amazonS3Exception.ErrorCode == "NoSuchKey") 
     { 
      return; 
     } 
     if (amazonS3Exception.ErrorCode != null && (amazonS3Exception.ErrorCode.Equals("InvalidAccessKeyId") || amazonS3Exception.ErrorCode.Equals("InvalidSecurity"))) 
     { 
      // Log AWS invalid credentials 
      throw new ApplicationException("AWS Invalid Credentials"); 
     } 
     else 
     { 
      // Log generic AWS exception 
      throw new ApplicationException("AWS Exception: " + amazonS3Exception.Message); 
     } 
    } 
    catch 
    { 
     // 
    } 
} 

圖像的下載一切工作正常,但Task.WaitAll似乎被忽略和代碼的其餘部分繼續執行 - 這意味着我嘗試獲取當前不存在的文件(因爲它們尚未下載)。

我發現this答案似乎與我的另一個問題。我試圖使用答案來更改我的代碼,但它仍然不會等待所有文件被下載。

誰能告訴我我哪裏出錯了嗎?

+0

答案如果你不是第一次添加的所有下載任務,只有* *事後**等待他們完成?這就是我的做法。你正在做的事情 - 在將一個新線程放入池中完成後立即等待 - 看起來像是同步編程 - 換句話說,你沒有從多線程中獲益。這不直接涉及*不等待*但是......我正在離開作爲一個評論。 – Veverke

+0

@Veverke我是Tasks的新手,所以我想如果我全部添加了它們,假設有10,000個文件需要下載,所有任務都會同時運行,並且系統處理太多了。 - 爲此我決定分批運行這些任務。 – Rick

+0

那麼我錯過了你有2次等待的事實,我只看到了第一次。然後,我現在問別的問題:爲什麼你需要循環內的那個?你有沒有嘗試過一次運行?嘗試評論for循環中的if,看看會發生什麼。你有例外嗎? – Veverke

回答

5

該代碼的行爲如預期。即使並非所有文件都已下載,在十秒後仍會返回Task.WaitAll,因爲您已在變量maxDownloadMilliseconds中指定了10秒(10000毫秒)的超時時間。

如果您確實想等待所有下載完成,請在不指定超時的情況下致電Task.WaitAll

使用

Task.WaitAll(tasks.ToArray());//wait to download 

在這兩個地方。

要了解關於如何實現並行下載,而不是強調系統中的一些好的解釋(只能並行下載的最大數量),請參閱How can I limit Parallel.ForEach?

+0

嗯......我假設10秒後,未完成的任務將被中止......讓我測試... – Rick

+1

未完成的任務不會中止,WaitAll只是在任務繼續在後臺運行時返回。 – NineBerry

+1

如果您希望任務中止,您必須在此遊戲中添加CancellationToken:o) –