我们正在编写一个小工具,该工具从我们的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(),那么它将像以前一样留下。
我考虑使用继续使用 - 但是该块内部该怎么办?它怎么知道所有其他文件都完成下载?
我什至考虑过将任务存储在集合中,并且在foreach循环的末尾编写了另一个循环,并在其上调用等待方法。
解决此类问题的正确方法是什么?
您可以将所有任务存储在集合中,然后致电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
我将使用Parallel.Foreach
使用单独的线程下载所有文件。
除非您真的需要/想要将所有下载的文件限制到一个大字符串中(并写入逻辑以稍后检索个体文件),我取而代之的是将字符串存储在线程安全列表中(sush as System.Collections.Collections.concurrent.concurrent.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);
});