【问题标题】:How to divide array of file paths into several smaller arrays?如何将文件路径数组划分为几个较小的数组?
【发布时间】:2012-08-01 18:29:33
【问题描述】:

我已经从 SO 阅读了几个关于此问题的不同问题,但仍然无法使其正常工作。我正在使用public static string[] files = Directory.GetFiles(CurrentDirectory, "*.wav", SearchOption.AllDirectories); 获取文件路径数组,然后将其传递给文件流。文件流所做的操作花费的时间太长,只有一个线程处理所有文件。所以我决定拆分数组并将这些较小的数组传递给不同的线程。

我使用的代码是从另一个 SO 问题中获得的,并使用它来传递拆分数组,但它仅适用于第一个数组中的一个文件,但我知道问题出在哪里:

var thing = from index in Enumerable.Range(0, files.Length) 
          group files[index] by index/600;
foreach(var set in thing)
    string.Join(";", set.ToArray());

(这不完全是我使用它的方式,我已经把它弄乱了,我不记得了。)这个问题是所有东西都被视为一个巨大的文件路径,我有一个 foreach 循环从较小的数组中获取每个文件,但它将其中的每个文件都视为一个文件,当搜索返回多个文件时抛出 filepathtoolong 异常。我的函数接受一个数组,然后使用foreach (string file in smallerArray) 写入每个数组。我需要做的是将文件数组分解为 4 个较小的数组并启动新线程,例如 new Thread(() => { DoWork(newArray); }).Start();,但我尝试过的都没有奏效。

【问题讨论】:

  • 您是否考虑过使用 Parallel LINQ 而不是自己编写?
  • @TimB:正是我发布的答案:)
  • 使用 Directory.EnumerateFiles() 作为源可能更好。
  • @Henk,谢谢,这有助于加快初始搜索速度。

标签: c# .net linq


【解决方案1】:

所以我决定拆分数组并将这些较小的数组传递给不同的线程。

听起来你做的很艰难 :) 让框架用Parallel.ForEach 为你处理它:

Parallel.ForEach(files, file => 
{
    // Do stuff with one file
});

【讨论】:

  • 我忘记了这个。我有几千个文件,这会为每个文件生成一个线程,对吧?同时运行这么多线程是否会对性能产生影响?或者在使用Parallel.ForEach时框架会限制并发运行的线程数吗?
  • @0_______0:很抱歉之前没有回复。不,它不会为每个文件生成一个线程。它为每个文件创建一个 task ,这不是一回事。这就像将任务添加到线程池中。不过,您可以明确限制并行度 - 特别是,如果这些文件位于同一个磁盘上,则不清楚任何并行度实际上是否会有所帮助。 (这也取决于磁盘类型。)
【解决方案2】:

这里是例子

    public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> source, int blockSize)
    {
        if (source == null)
            throw new ArgumentNullException("source");
        if (blockSize <= 0)
            throw new ArgumentException("blockSize = {0}".FormatWith(blockSize), "blockSize");
        var result = new List<IEnumerable<T>>();
        for (int blockStartIndex = 0; blockStartIndex < source.Count(); blockStartIndex += blockSize)
        {
            int blockStart = blockStartIndex;
            int blockEnd = blockStartIndex + blockSize - 1;
            IEnumerable<T> block = source.Where((x, i) => i >= blockStart && i <= blockEnd);
            result.Add(block);
        }
        return result;
    }

这里是测试

    [Test]
    public void TestSplit()
    {
        var list = new[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
        IEnumerable<IEnumerable<int>> splitted = list.Split(10);
        Assert.That(splitted.Count(), Is.EqualTo(1));
        Assert.That(splitted.First().Count(), Is.EqualTo(10));

        splitted = list.Split(11);
        Assert.That(splitted.Count(), Is.EqualTo(1));
        Assert.That(splitted.First().Count(), Is.EqualTo(10));

        splitted = list.Split(9);
        Assert.That(splitted.Count(), Is.EqualTo(2));
        Assert.That(splitted.First().Count(), Is.EqualTo(9));
        Assert.That(splitted.ElementAt(1).Count(), Is.EqualTo(1));

        splitted = list.Split(3);
        Assert.That(splitted.Count(), Is.EqualTo(4));
        Assert.That(splitted.First().Count(), Is.EqualTo(3));
        Assert.That(splitted.ElementAt(1).Count(), Is.EqualTo(3));
        Assert.That(splitted.ElementAt(2).Count(), Is.EqualTo(3));
        Assert.That(splitted.ElementAt(3).Count(), Is.EqualTo(1));
    }

【讨论】:

    猜你喜欢
    • 2023-03-03
    • 2010-12-09
    • 1970-01-01
    • 2021-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多