【问题标题】:Tying it all together, Directory Recursive Search + Events + Threading将它们结合在一起,目录递归搜索 + 事件 + 线程
【发布时间】:2014-03-20 13:02:51
【问题描述】:

我想做并且一直致力于开发的是一个标准类,我可以使用它来检索所有子目录(及其子目录和文件等)和文件。

WalkthroughDir(Dir)
  Files a
  Folders b
  WalkthroughDir(b[i])

简单的递归目录搜索。

以此为基础,我想将其扩展为在以下情况下触发事件:

  • 找到一个文件;
  • 找到一个目录;
  • 搜索完成

    private void GetDirectories(string path)
    {
        GetFiles(path);
    
        foreach (string dir in Directory.EnumerateDirectories(path))
        {
            if (DirectoryFound != null)
            {
                IOEventArgs<DirectoryInfo> args = new IOEventArgs<DirectoryInfo>(new DirectoryInfo(dir));
                DirectoryFound(this, args);
            }
    
            // do something with the directory...
    
            GetDirectories(dir, dirNode);
        }
    }
    
    private void GetFiles(string path)
    {
        foreach (string file in Directory.EnumerateFiles(path))
        {
            if (FileFound != null)
            {
                IOEventArgs<FileInfo> args = new IOEventArgs<FileInfo>(new FileInfo(file));
                FileFound(this, args);
            }
    
            // do something with the file...
        }
    }
    

上面的 cmets(“做某事 [...]”)是我可以将文件或目录添加到某些数据结构的位置。

进行此类搜索的最常见因素是处理时间,尤其是对于大型目录。所以很自然地,我想再向前迈出一步并实现线程。现在,我对线程的了解非常有限,但到目前为止,这是我想出的大纲:

    public void Search()
    {
        m_searchThread = new Thread(new ThreadStart(SearchThread));
        m_searching = true;
        m_searchThread.Start();
    }

    private void SearchThread()
    {
        GetDirectories(m_path);
        m_searching = false;
    }

如果我使用此实现,则在控件中分配事件,它会抛出错误(如我所料),我的 GUI 应用程序正在尝试访问另一个线程。

任何人都可以对此实现以及如何完成线程提供反馈。谢谢。

更新(selkathguy 推荐):

这是根据 selkathguy 的建议调整后的代码:

    private void GetDirectories(DirectoryInfo path)
    {
        GetFiles(path);

        foreach (DirectoryInfo dir in path.GetDirectories())
        {
            if (DirectoryFound != null)
            {
                IOEventArgs<DirectoryInfo> args = new IOEventArgs<DirectoryInfo>(dir);
                DirectoryFound(this, args);
            }

            // do something with the directory...

            GetDirectories(dir);
        }
    }

    private void GetFiles(DirectoryInfo path)
    {
        foreach (FileInfo file in path.GetFiles())
        {
            if (FileFound != null)
            {
                IOEventArgs<FileInfo> args = new IOEventArgs<FileInfo>(file);
                FileFound(this, args);
            }

            // do something with the file...
        }
    }

原码耗时:47.87s

修改后的代码耗时:46.14s

【问题讨论】:

    标签: c# multithreading recursion io


    【解决方案1】:

    要解决关于从标准类引发您自己的事件的请求的第一部分:您可以创建一个委托,其他方法可以作为事件的回调挂钩到该委托。请参阅http://msdn.microsoft.com/en-us/library/aa645739(v=vs.71).aspx 作为一个很好的资源。实现起来相当简单。

    至于线程,我相信至少对于您的性能问题来说这是不必要的。递归检查目录的大部分性能瓶颈是等待从磁盘加载节点信息。相对而言,这会占用您所有的时间,因为获取目录信息是一个阻塞过程。让多个线程都检查不同的目录很容易降低搜索的整体速度,并且会使您的应用程序与工作线程的管理和工作共享的委派变得非常复杂。话虽如此,如果您的搜索跨越多个磁盘或资源位置,则每个磁盘都有一个线程可能是可取的。

    我发现像使用 DirectoryInfo.GetDirectories() 进行递归这样简单的方法是最快的解决方案之一,因为它利用了 Windows 已经具备的缓存功能。我用它做的一个搜索应用,每秒可以搜索上万个文件名和目录名。

    【讨论】:

    • 所以我用 DirectoryInfo 替换了字符串,并使用了您建议的方法。在运行两者之后,使用我的原始实现需要 478717867 滴答声,而根据您的建议,它需要 461456141。两者似乎都没有重大区别。关于线程,我假设只有一个线程在运行,即“m_searchThread”。显然创建类的新实例会产生更多,但我不认为这是一个负担。
    • 我已经更新了帖子以包含更新的内容,以便您查看它的外观以及这是否符合您的意图。
    • 就像我说的,主要的性能问题将是物理磁盘,而不是在这种情况下您的应用程序。至于线程,如果我理解正确,您需要另一个线程,因为您是从 UI 线程运行它,并且您不想阻止它,这是可以理解的。我用基于 UI 的搜索做了类似的事情,我创建了一个搜索线程,然后只是偶尔使用locking 围绕一个进度变量,并在调用 UI 线程的设定时间间隔进行检查。不是最优雅的,但它非常简单,而且效果很好。
    • 我认为它已经被证明了,因为我怀疑递归就是递归,无论使用字符串调用静态“GetDirectories”还是创建 DirectoryInfo 实例并检索它都需要一段时间.即使它确实为我节省了足够多的时间~1 秒!我的目标是目录搜索的通用类。所以我需要尽可能保持通用性,包括用于搜索的线程模型。你有任何具体的例子、代码参考等吗?正如我所说,我对线程的了解是有限的,所以我需要一些更具体的东西。
    • 绝对! pastebin.com/QM87TQci 请注意,我给出的示例包含您可能需要或不需要的功能,因为它只是直接摘自我的代码。
    猜你喜欢
    • 1970-01-01
    • 2016-09-06
    • 2013-06-17
    • 1970-01-01
    • 2010-12-01
    • 2012-04-07
    • 1970-01-01
    • 2011-08-15
    相关资源
    最近更新 更多