如何减慢整个磁盘扫描进程?

时间:2015-07-26 11:36:29

标签: c# file search io

我开发的应用程序曾经有一段时间(主要是在重启后)必须搜索整个驱动​​器,以检查自上次重启后具有给定扩展名的文件是否发生了变化。

起初,所有内容似乎都按预期工作,但过了一段时间后,原来并非所有用户都这样。他们中的一些人开始抱怨他们的计算机在重启后的前几分钟内几乎被冻结了。原因是巨大的磁盘活动(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>();
    }
}

2 个答案:

答案 0 :(得分:4)

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

然后,在扫描过程中,您可以通过按照Michal在评论中建议的每N次迭代添加{{1}}来减慢速度。

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

答案 1 :(得分:0)

使扫描算法经常轮询PauseToken。定时器每1000毫秒发出一次100ms的信号。这使计算机有10%的空闲时间。

这是一个简单的变体。一个更好的变体是在没有计时器的情况下做出应有但是需要用更长的时间来计算。