我正在创建一个应用程序,我想根据xslx文件的内容重命名一堆文件夹中的一堆文件。
我正在制作一个并行for循环,其中每个文件夹都有自己的“线程”(或whatchamacallit),然后应用程序应根据文件夹名称检索xlsx文件中的所有帖子以及相应的文件夹名称和根据从xlsx文件获取的内容重命名文件夹的内容。我希望这是有道理的。
我的问题是:我应该何时阅读xlsx文件?在我看来,我有两个选择:1)在并行迭代之前打开文件,让每个迭代循环遍历文件的内容,寻找文件夹名称。可能的问题可能是多个线程将同时检查同一个数组。我不知道是否可以捏造东西。 2)为每次迭代打开一次文件并循环查找结果。我认为多次打开文件会比以前更耗时。
xlsx文件包含大约48000行数据。
编辑:
由于评论和答案建议我并解释原因,我已经删除了并行for循环并且定期删除。但我会留下让其他人找到的问题。
问题是:我什么时候应该打开xlsx文件? (有关详细信息,请参阅预编辑)
答案 0 :(得分:1)
不应将多线程用于I / O绑定操作。即使您使用非常快速的存储设备(如SSD或RAID),也不会从多线程中获得太多的性能提升。对于常规硬盘驱动器,性能实际上会变差。例如,尝试同时复制多个文件或提取多个zip存档。由于多个线程不断争夺单个I / O设备,您很快就会注意到性能下降。
答案 1 :(得分:1)
我进行了一些测试,看看你可能获得什么样的性能提升,如果有的话。我决定创建10,000个文件,并使用Stopwatch
计算重命名文件所需的时间。我使用了单线程和多线程方法。
以下是代码:
//var path = @"D:\Users\Enigmativity\Temporary\SOTest"; //HDD
var path = @"C:\_temporary\SOTest"; //SSD
var files = 10000;
var format = "00000";
var rnd = new Random();
Enumerable
.Range(0, files)
.OrderBy(n => rnd.NextDouble())
.ForEach(n => File.WriteAllText(System.IO.Path.Combine(path, n.ToString(format) + ".txt"), n.ToString()));
然后我跑了这个:
var sw = Stopwatch.StartNew();
Enumerable
.Range(0, files)
.ToList()
.ForEach(n =>
System.IO.File.Move(
System.IO.Path.Combine(path, n.ToString(format) + ".txt"),
System.IO.Path.Combine(path, n.ToString(format) + n.ToString(format) + ".txt")));
sw.Stop();
并将其与此进行比较:
var sw = Stopwatch.StartNew();
Enumerable
.Range(0, files)
.GroupBy(x => 10 * x / files)
.AsParallel()
.ForAll(ns =>
ns
.ToList()
.ForEach(n =>
System.IO.File.Move(
System.IO.Path.Combine(path, n.ToString(format) + ".txt"),
System.IO.Path.Combine(path, n.ToString(format) + n.ToString(format) + ".txt"))));
sw.Stop();
在每次运行结束时,我清理了文件:
Directory.EnumerateFiles(path).ForEach(x => File.Delete(x));
我的结果是:
Single thread on HDD: 2,155 milliseconds
Multi-threads on HDD: 1,601 milliseconds
Single thread on SSD: 2,457 milliseconds
Multi-threads on SSD: 940 milliseconds
我多次运行这些结果,每次运行大致是同一时间。我从并行运行的SSD中获得了巨大的好处,并且在HDD上获得了适度的好处。
答案 2 :(得分:0)
只需从数据结构中读取即可同时执行。这不是问题。我看到的问题是,如果你不在列表上执行任何预处理,你将从许多线程中扫描它多次,这是一种浪费。那怎么样:
var excelItems = ...; //Fill this in.
var groupedbyFolder = excelItems.GroupBy(x => x.directoryName);
groupedByFolder.AsParallel().ForAll(g => ProcessFolder(g));
这只会遍历一次数据,非常简单易用。
您还需要将AsParallel
配置为经验确定的并行度。尝试不同的值。