【问题标题】:How to slow down full disk scan process?如何减慢全盘扫描过程?
【发布时间】:2015-07-26 11:36:28
【问题描述】:

我正在开发一个应用程序,它有时(主要是在重新启动后)必须搜索整个驱动​​器以检查具有给定扩展名的文件自上次重新启动后是否已更改。

起初一切似乎都按预期工作,但过了一段时间后发现并非对所有用户都适用。他们中的一些人开始抱怨他们的计算机在重新启动后的最初几分钟内几乎被冻结。原因是巨大的磁盘活动 (I\O)。

所以我有一个不寻常的问题,如何减慢完整扫描过程? 我正在使用下面的代码。我应该使用 Sleep 方法还是更改逻辑?

public static IEnumerable<string> GetFiles(string rootFolderPath, Regex fileSearchPattern, SearchOption searchOpt)
{
    Queue<string> pending = new Queue<string>();
    pending.Enqueue(rootFolderPath);
    IEnumerable<string> tmp;

    while (pending.Count > 0)
    {
        rootFolderPath = pending.Dequeue();

        tmp = EnumerateFiles(rootFolderPath, searchOpt)
              .Where(file => fileSearchPattern.IsMatch(
                  Path.GetExtension(file)
              ));

        foreach (string file in tmp)
        {
            yield return file;
        }
    }
}

public static IEnumerable<string> GetDirectories(string rootFolderPath, string directoryName, Regex directorySearchPattern, SearchOption searchOpt)
{
    foreach (string directory in EnumerateDirectories(rootFolderPath, directoryName, searchOpt)
                                .Where(d => directorySearchPattern.IsMatch(d + @"\")))
    {
        yield return directory;
    }
}

public static IEnumerable<string> EnumerateFiles(string path,  SearchOption searchOpt)
{
    try
    {
        var dirFiles = Enumerable.Empty<string>();
        if (searchOpt == SearchOption.AllDirectories)
        {
            dirFiles = System.IO.Directory.EnumerateDirectories(path)
                                .SelectMany(x => EnumerateFiles(x, searchOpt));
        }
        return dirFiles.Concat(System.IO.Directory.EnumerateFiles(path));
    }
    catch (IOException)
    {
        return Enumerable.Empty<string>();
    }
    catch (UnauthorizedAccessException)
    {
        return Enumerable.Empty<string>();
    }
}

public static IEnumerable<string> EnumerateDirectories(string parentDirectory, string searchPattern, SearchOption searchOpt)
{
    try
    {
        var directories = Enumerable.Empty<string>();
        if (searchOpt == SearchOption.AllDirectories)
        {
            directories = System.IO.Directory.EnumerateDirectories(parentDirectory)
                .SelectMany(x => EnumerateDirectories(x, searchPattern, searchOpt));
        }
        return directories.Concat(System.IO.Directory.EnumerateDirectories(parentDirectory));
    }
    catch (IOException)
    {
        return Enumerable.Empty<string>();
    }
    catch (UnauthorizedAccessException)
    {
        return Enumerable.Empty<string>();
    }
}

【问题讨论】:

  • 所有这些 DIY 递归代码是否有特定原因,而不是仅仅将 AllDirectories 传递给 Directory.EnumerateFiles() ?
  • 当我尝试仅使用 Directory.EnumerateFiles() 我收到 UnauthorizedAccessException
  • 也许你应该有另一种方法,例如有一个订阅文件更改的服务,请参阅msdn.microsoft.com/en-us/library/… 这样您就不需要在重新启动时打扰用户,我们用户都不太喜欢等待
  • 当我尝试仅使用 Directory.EnumerateFiles() 时,我收到 UnauthorizedAccessException 捕获并忽略它!它来自受限制的文件夹..
  • 为什么不保留一个计数器来记录你做了多少操作,每 x 操作你做一个Thread.Sleep(x) e.g. if(counter % 100 == 0) Thread.Sleep(100)。在您的foreach 中,您递增计数器。

标签: c# file search io


【解决方案1】:

我要做的第一件事是延迟此操作的开始。操作系统启动已经完成了很多 I/O 工作,因此同时运行一个 I/O 密集型进程可能不是一个好主意。在开始扫描磁盘之前可能要睡 1 到 2 分钟。

然后,在扫描过程中,您可以按照 Michal 在 cmets 中的建议,通过每 N 次迭代添加一个Sleep 来减慢它。

另一个更复杂的选项是分析 NTFS 日志以查看哪些文件已更改。但请注意,它需要管理员权限,因此您的进程必须以提升的权限运行(您可以将其设为服务,这样它就不需要每次都需要 UAC 确认)。

【讨论】:

    【解决方案2】:

    使扫描算法频繁轮询PauseToken。使计时器每 1000 毫秒向令牌发出 100 毫秒的信号。这使计算机有 10% 的空闲时间。

    这是简单的变体。更好的变体是在没有计时器的情况下到期,但这需要计算持续时间,这更难。

    【讨论】:

      猜你喜欢
      • 2012-04-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-19
      • 1970-01-01
      • 1970-01-01
      • 2015-07-16
      • 1970-01-01
      相关资源
      最近更新 更多