我们正在编写一个小工具,从我们的Web服务器下载文件并对其进行分析。这是一个很多文件,下载大约需要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循环结束时编写另一个循环,它接受所有任务并调用wait方法。
解决此类问题的正确方法是什么?
答案 0 :(得分: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 :(得分:1)
我会使用Parallel.Foreach
使用单独的线程下载所有文件。
除非你真的需要/想要将所有下载的文件连接成一个大字符串,(并编写逻辑以便以后检索单个文件),否则我将字符串存储在线程安全列表中(sush as 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);
});