2014-01-28 64 views
2

後,我們正在寫一個小工具,可以從我們的網站服務器下載文件,並對其進行分析。這是一個很大的文件,大約需要10分鐘下載,我們希望通過允許應用程序下載並行文件,以使下載時間更短。下載多個文件在同一時間,並繼續所有文件下載完畢

目前我們有一個循環的越過文件列出要下載,只是下載它們並添加文件名來分隔字符串:

foreach (var File in ServerFiles) 
{ 
    string sFileName = File.Uri.LocalPath.ToString(); 
    // some internal logic and initialization 
    oBlob.DownloadToStream(fileStream); 
    sFiles += sFileName.Replace("/" + Container + "/", "") + ","; 
} 

我們把它改爲:

foreach (var File in ServerFiles) 
{ 
    string sFileName = File.Uri.LocalPath.ToString(); 
    // some internal logic and initialization 
    Task downloadTask = oBlob.DownloadToStreamAsync(fileStream); 
    sFiles += sFileName.Replace("/" + Container + "/", "") + ","; 
} 

現在我的問題是什麼,我的任務做我回去。如果我只是調用downloadTask.wait(),那麼它就像以前一樣。

我想過使用continueWith - 但應該是塊內呢?它會如何知道所有其他文件已完成下載?

我甚至想過在一個集合中存儲任務,並在foreach循環結束時編寫另一個循環,它接受所有任務並調用它們的等待方法。

什麼是解決這個問題的正確方法是什麼?

+2

你確定平行下載它們會更快嗎?你是否確定了瓶頸?源磁盤,網絡,目標磁盤?並行性如何改善瓶頸? –

+0

如果所有文件確實在同一臺服務器上,則還需要增加['ServicePointManager.DefaultConnectionLimit'](http://msdn.microsoft.com/zh-cn/library/system.net.servicepointmanager.defaultconnectionlimit) 。 – svick

回答

2

您可以將所有任務存儲在集合中,然後致電 Task.WaitAll(yourArray); 您的代碼將被阻止,直到完成所有任務。 事情是這樣的:

var tasks=new List<Task>(); 
foreach (var File in ServerFiles) 
{ 
    string sFileName = File.Uri.LocalPath.ToString(); 
    // some internal logic and initialization 
    Task downloadTask = oBlob.DownloadToStreamAsync(fileStream); 
tasks.Add(downloadTask); 
    sFiles += sFileName.Replace("/" + Container + "/", "") + ","; 
} 
Task.WaitAll(tasks); 
//Continue here 
1

我會用Parallel.Foreach來下載使用單獨的線程中的所有文件。除非你真的需要/想要將所有下載的文件連接成一個大字符串(並且編寫邏輯以稍後檢索個別文件),否則我將字符串存儲在線程安全列表中(sush作爲System.Collections。 Concurrent.ConcurrentBag允許多個線程寫入列表)。

ConcurrentBag<string> downloadedFiles = new ConcurrentBag<string>(); 

Parallel.ForEach(ServerFiles, file => 
{ 
    string sFileName = file.Uri.LocalPath.ToString(); 
    // some internal logic and initialization 
    oBlob.DownloadToStream(fileStream); 
    downloadedFiles.Add(sFileName); 
});