C#中的多线程目录循环

Ale*_*rge 4 .net c# recursion

我试图遍历所有文件和文件夹,并对具有特定扩展名的所有文件执行操作.这种方法工作正常,但我想让它多线程,因为当完成数以万计的文件时,它真的很慢,我会使用多线程进行成像会加快速度.在这种情况下,我只是不确定如何使用线程.

doStuff 从文件中读取属性(修改日期等,并将它们插入到sqlite数据库中.我在调用扫描方法之前启动一个事务,以便尽可能地优化它.

提供有关如何执行此操作的理论的答案与完整的代码答案一样好.

    private static string[] validTypes = { ".x", ".y", ".z", ".etc" };
    public static void scan(string rootDirectory)
    {
        try
        {

            foreach (string dir in Directory.GetDirectories(rootDirectory))
            {

                if (dir.ToLower().IndexOf("$recycle.bin") == -1)
                    scan(dir);
            }

            foreach (string file in Directory.GetFiles(rootDirectory))
            {

                if (!((IList<string>)validTypes).Contains(Path.GetExtension(file)))
                {
                    continue;
                }


                doStuff(file);
            }
        }
        catch (Exception)
        {
        }
    }
Run Code Online (Sandbox Code Playgroud)

SLa*_*aks 5

假设doStuff是线程安全的,而且你不需要等待整个扫描完成,你可以打电话都doStuffscan上线程池,如下所示:

string path = file;
ThreadPool.QueueUserWorkItem(delegate { doStuff(path); });
Run Code Online (Sandbox Code Playgroud)

您需要创建一个单独的局部变量,因为匿名方法file本身会捕获变量,并且会在整个循环中看到对它的更改.(换句话说,如果ThreadPool仅在循环继续到下一个文件后执行任务,它将处理错误的文件)

但是,阅读你的评论,这里的主要问题是磁盘IO,所以我怀疑多线程不会有多大帮助.

请注意,Directory.GetFiles对于具有大量文件的目录,执行速度会很慢.(因为它需要分配一个数组来保存文件名)
如果您正在使用.Net 4.0,您可以通过调用该EnumerateFiles方法来加快速度,它使用迭代器返回一个IEnumerable<string>在运行循环时枚举目录的方法.
您还scan可以通过传递SearchOption参数来避免使用任一方法进行递归调用,如下所示:

foreach (string file in Directory.EnumerateFiles(rootDirectory, "*", SearchOption.AllDirectories))
Run Code Online (Sandbox Code Playgroud)

这将递归扫描所有子目录,因此您只需要一个foreach循环.
请注意,这会加剧性能问题GetFiles,因此您可能希望避免使用此preNet.Net 4.0.