如何加快目录搜索速度

时间:2018-05-27 04:03:18

标签: c#

编写一个将文件目录作为输入的查找最大方法。循环通过目录文件并搜索100 + rnd之后的最大值。但是我有很多文件,所以需要一段时间。加快速度的最佳方法是什么?不太确定最好的解决方案。可能是一种线程池?这就是我所拥有的。另外,请假设该行在转换为int之前已经过验证。感谢。

编辑:文件的每一行都有一个int。不仅每个文件一个。 编辑2:操作目前约为900毫秒,理想情况下需要降低400%。

public static int FindLargest()
{
    var files = Directory.GetFiles(@"C:\Dir");

    List<int> values = new List<int>();

    foreach (var fileName in files)
    {
        var file = File.ReadAllLines(fileName);

        foreach(var line in file)
        {
            int product = PerformAddition(Convert.ToInt32(line));

            if(product >= 100) values.Add(product);
        }
    }

    int largest = 0;
    foreach(int value in values)
    {
        if(value > largest) largest = value;
    }

    return largest;
}

public static int PerformAddition(int value)
{
    var rnd = new Random();

    return value + rnd.Next(0, 100);
}

2 个答案:

答案 0 :(得分:3)

比赛你的马!

所以前提是再次测试原始版本的其他一些解决方案

测试进行了100多个文件并运行10次。比例是文件中的多少行内容

最后,我删除了随机,以便我可以验证结果

结果

Mode            : Release
Test Framework  : .NET Framework 4.7.1
Benchmarks runs : 10 times (averaged)

Scale : 100
Name         |   Average |  Fastest | StDv |     Cycles | Pass
-----------------------------------------------------------------
Mine4        |  2.323 ms | 2.191 ms | 0.13 |  2,241,488 | Yes
johnPlusMine |  2.676 ms | 2.064 ms | 0.33 |  6,117,891 | Yes
john         |  3.124 ms | 2.723 ms | 0.27 |  8,914,485 | Yes
Original     | 10.004 ms | 9.146 ms | 0.71 | 34,025,586 | Base
Mine3        | 10.279 ms | 7.012 ms | 2.45 | 31,679,870 | Yes


Scale : 1,000
Name         |   Average |   Fastest | StDv |      Cycles | Pass
-------------------------------------------------------------------
Mine4        |  4.037 ms |  3.363 ms | 0.45 |   2,566,176 | Yes
johnPlusMine |  4.606 ms |  3.040 ms | 1.61 |  10,893,833 | Yes
john         |  8.307 ms |  7.118 ms | 0.70 |  18,582,130 | Yes
Mine3        | 11.023 ms |  9.498 ms | 1.61 |  37,394,603 | Yes
Original     | 33.316 ms | 23.887 ms | 8.29 | 108,467,775 | Base


Scale : 10,000
Name         |    Average |    Fastest | StDv |      Cycles | Pass
---------------------------------------------------------------------
johnPlusMine |  12.643 ms |  11.908 ms | 0.62 |  21,985,225 | Yes
Mine4        |  12.655 ms |  11.074 ms | 1.00 |   2,482,408 | Yes
Mine3        |  38.223 ms |  37.495 ms | 0.83 | 130,130,301 | Yes
john         |  53.337 ms |  47.496 ms | 3.79 | 126,151,357 | Yes
Original     | 194.628 ms | 185.462 ms | 9.20 | 660,359,390 | Base


Scale : 100,000
Name         |      Average |      Fastest |  StDv |        Cycles | Pass
----------------------------------------------------------------------------
johnPlusMine |   195.336 ms |   179.742 ms | 12.09 |   166,869,434 | Yes
Mine4        |   209.209 ms |   180.388 ms | 22.50 |     3,220,582 | Yes
Mine3        |   331.211 ms |   313.332 ms | 19.35 | 1,097,353,237 | Yes
john         |   489.939 ms |   455.913 ms | 26.35 |   910,277,113 | Yes
Original     | 2,877.904 ms | 2,845.898 ms | 31.42 | 9,584,556,134 | Base

我的3

基本上这是使用指针和手动解析的unsafe fixed版本

protected override unsafe int InternalRun()
{
   var largest = int.MinValue;

   var files = Directory.GetFiles(@"D:\ints");
   foreach (var file in files)
   {
      var content = File.ReadAllText(file);

      fixed (char* pContent = content)
      {
         var len = pContent + content.Length;
         var current = 0;

         for (var p = pContent; p < len; p++)
         {
            if (*p >= 48)
            {
               current = current * 10 + *p - 48;
            }
            else
            {
               if (current > largest)
               {
                  largest = current;
               }
               current = 0;
               p++;
            }
         }

         current = 0;
         if (current > largest)
         {
            largest = current;
         }
      }
   }

   return largest;
}

Mine4

这使用ActionBlocksunsafe

private static volatile int _max = int.MinValue;

private static readonly object _sync = new object();

public static async Task<int> DoWorkLoads(string[] files)
{
   var options = new ExecutionDataflowBlockOptions
                     {
                        MaxDegreeOfParallelism = 50
                     };

   var block = new ActionBlock<string>((Action<string>)MyMethodAsync, options);

   foreach (var file in files)
   {
      block.Post(file);
   }

   block.Complete();
   await block.Completion;
   return _max;
}

unsafe public static void MyMethodAsync(string fileName)
{

      var largest = int.MinValue;
      var content = File.ReadAllText(fileName);

      fixed (char* pContent = content)
      {
         var len = pContent + content.Length;
         var current = 0;

         for (var p = pContent; p < len; p++)
         {
            if (*p >= 48)
            {
               current = current * 10 + *p - 48;
            }
            else
            {
               if (current > largest)
               {
                  largest = current;
               }
               current = 0;
               p++;
            }
         }

         current = 0;
         if (current > largest)
         {
            largest = current;
         }
      }

      lock (_sync)
      {
         if (largest > _max)
         {
            _max = largest;
         }
      }

}

protected override int InternalRun()
{
   _max = 0;
   var files = Directory.GetFiles(@"D:\ints");
   var result = DoWorkLoads(files)
      .Result;
   return result;
}

JohnPlusMine

private static object _sync = new object();

private static int _max;

public static unsafe void MyMethodAsync(string fileName)
{
   var largest = int.MinValue;
   var content = File.ReadAllText(fileName);

   fixed (char* pContent = content)
   {
      var len = pContent + content.Length;
      var current = 0;

      for (var p = pContent; p < len; p++)
      {
         if (*p >= 48)
         {
            current = current * 10 + *p - 48;
         }
         else
         {
            if (current > largest)
            {
               largest = current;
            }
            current = 0;
            p++;
         }
      }

      current = 0;
      if (current > largest)
      {
         largest = current;
      }
   }

   lock (_sync)
   {
      if (largest > _max)
      {
         _max = largest;
      }
   }
}

protected override int InternalRun()
{
   var files = Directory.GetFiles(@"D:\ints");

   Parallel.ForEach(files, MyMethodAsync);

   return _max;
}

进一步说明

我的其他尝试是使用async await和动作块,其想法是让IO绑定任务成为IO绑定任务,但结果并不公平。最后,如果我使用Parallel.ForEarch,我可能会获得更快的速度,但是我的能量耗尽了。

无论如何,如果你要使用不安全的版本,你需要设置项目在属性中使用不安全的代码,也没有错误检查,所以如果你输入垃圾它将输出垃圾。此外,您可能想要调整MaxDegreeOfParallelism以获得最大的效果。

老实说,你可能更好地与约翰回答,除非你试图挤出最后一点表现,否则它更直接

原帖

这样做

// var content = File.ReadAllLines(file);

基本上,您正在阅读文件的内容,无明显原因

答案 1 :(得分:1)

你可以像这样重写它:

public static int FindLargest()
{
    var files = Directory.GetFiles(@"C:\Dir");

    int largest = 0;
    Object lockObject = new object();

    Parallel.ForEach(files, file =>
    {
        foreach (var line in File.ReadLines(file))
        {
            int product = PerformAddition(Convert.ToInt32(line));
            if (product < 100)
            {
                continue;
            }
            if (product > largest)
            {
                lock(lockObject)
                {
                    if (product >  largest)
                    {
                        largest = product;
                    }
                }
            }
        }
    });

    return largest;
}

它并行运行每个文件,并枚举行而不是将它们全部加载到内存中。由于您只想要最大的值,因此我避免将值存储在内存中,以便随时跟踪最大值。

对于文件的每一行我们:

  1. 如果值为&lt; 100
  2. 检查产品是否&gt;最大
  3. 锁定以获得对内部代码块的独占访问权限(因此,一次只有一个线程可以更新largest
  4. 再次检查产品&gt;最大的(另一个线程可能在我们等待锁定时更新了值)。
  5. 最后,我们返回最大值。

    由于Random类默认使用当前系统时间的种子进行初始化,因此您可能会获得重复的随机值。我已经编写了一些代码,这些代码将为每个线程创建一个新的Random实例(因为我的方法是多线程的。如果你使用非多线程方法,你可以只使用一个{{{ 1}}):

    Random

    在我的系统测试中(SSD,i7 4770k),我可以在750毫秒内始终处理100个文件,总大小约为75兆字节。就行而言,它每毫秒约为7500行。