2017-04-19 88 views
1

我有一個簡單的文件下載器,我從服務器獲取一些文件,然後顯示一條消息,通知它是成功還是失敗。下面的代碼:等待Task.WhenAll似乎完成,但它永遠不會到達下一行代碼

public async Task GetFiles(IEnumerable<string> urlList) 
{ 
    //some variable declaring, setting etc. 

    await Task.WhenAll(urlList.Select(url => Task.Run(() => DownloadFile(url, dir, count++))).ToList()); 
    //problem lies here, the WhenAll never completes 
    if (fileDownloadError) 
    { 
     Directory.Delete(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "downloads")); 
     MessageBox.Show("Fail"); 
     return; 
    } 
    MessageBox.Show("Success"); 
} 

internal async Task DownloadFile(string url, string dir, int count) 
{ 
    string filename = HelperClass.GetFilenameFromUrl(url); 
    long a = 0; 
    newList.Add(a); 
    using (var client = new WebClient()) 
    { 
     TempDownload tp = new TempDownload() 
     { 
      id = count 
     }; 

     client.DownloadProgressChanged += new DownloadProgressChangedEventHandler((sender, e) => ProgressChanged(sender, e, tp)); 
     client.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed); 

     await client.DownloadFileTaskAsync(url, string.Concat(dir, "\\", filename)); 
    } 
} 

ProgressBarDownloadProgressChanged事件改變達到100%,文件被正確下載,但代碼中的WhenAll從未執行後,也就是它從來沒有擊中if (fileDownloadError)斷點,沒有消息框顯示等。有什麼我在這裏失蹤?

+0

放置代碼,看看你得到一個異常 – jdweng

+0

也許有些線程異常在你的代碼中。註釋掉「DownloadProgressChaged」和「DownloadFileCompleted」事件,看看它是否有效。如果有效,問題出在這些事件處理程序上。 – AjS

+0

@jdweng我試過了,沒有,它從來沒有捕捉到任何東西,只是愉快地掛在WhenAll -AjS註釋事件處理程序除了阻止相關的進度條工作之外沒有任何作用 – Janushoff

回答

2

由於死鎖,斷點從不碰撞if語句。將ConfigureAwait(false)添加到所有等待中。 EX-

await Task.WhenAll(urlList.Select(url => Task.Run(() => DownloadFile(url, dir, count++))).ToList()).ConfigureAwait(false); 

await client.DownloadFileTaskAsync(url, string.Concat(dir, "\\", filename)).ConfigureAwait(false); 

另一個optionto解決這個問題是,不使用等待或UI線程的結果。使用異步地等待着異常處理程序

EX-

private async void button1_Click(object sender, EventArgs e) 
{ 
      await GetFiles(); 
}  

對於細節,

https://msdn.microsoft.com/en-us/magazine/gg598924.aspx

https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

+0

這確實會解除代碼,謝謝。然而,我將不得不閱讀一下你提供的內容來理解爲什麼它首先鎖定了鎖。 – Janushoff

+0

簡而言之,死鎖細節:UI線程正在等待任務完成。當任務完成並準備好返回到UI線程時,發生死鎖。 UI線程等待任務完成並在UI線程上等待任務。通過使用ConfigureAwait(false),任務可以繼續使用線程池中的任何線程(不會等待UI線程)。 – Kaushal

+1

另一個解決此問題的方法是不在UI線程上使用Wait或Result。在UI線程中使用異步等待 – Kaushal