并行循环和读取将在多个线程中使用的文件,最佳做法?

时间:2015-10-15 11:13:12

标签: c# multithreading parallel-processing readfile

我正在创建一个应用程序,我想根据xslx文件的内容重命名一堆文件夹中的一堆文件。

我正在制作一个并行for循环,其中每个文件夹都有自己的“线程”(或whatchamacallit),然后应用程序应根据文件夹名称检索xlsx文件中的所有帖子以及相应的文件夹名称和根据从xlsx文件获取的内容重命名文件夹的内容。我希望这是有道理的。

我的问题是:我应该何时阅读xlsx文件?在我看来,我有两个选择:1)在并行迭代之前打开文件,让每个迭代循环遍历文件的内容,寻找文件夹名称。可能的问题可能是多个线程将同时检查同一个数组。我不知道是否可以捏造东西。 2)为每次迭代打开一次文件并循环查找结果。我认为多次打开文件会比以前更耗时。

xlsx文件包含大约48000行数据。

编辑:

由于评论和答案建议我并解释原因,我已经删除了并行for循环并且定期删除。但我会留下让其他人找到的问题。

问题是:我什么时候应该打开xlsx文件? (有关详细信息,请参阅预编辑)

3 个答案:

答案 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配置为经验确定的并行度。尝试不同的值。