C# C代码需要很长时间才能运行。有没有办法让它更快完成?

C# C代码需要很长时间才能运行。有没有办法让它更快完成?,c#,multithreading,recursion,subdirectory,C#,Multithreading,Recursion,Subdirectory,我需要一些帮助。如果您在我的代码中输入一个目录,它将进入该目录中的每个文件夹并获取每个文件。通过这种方式,我通过使用代码绕过了“AccessDeniedException”,但是如果目录是一个包含大量数据和文件夹(例如:C:/)的目录,则需要花费大量的时间 我真的不知道如何使用多线程,在互联网上也找不到任何帮助。有没有办法通过多线程使代码运行得更快?或者可以要求代码使用更多内存或内核吗?我真的不知道,我需要你的建议 在每个子目录的每个文件中输入的代码: public static List<

我需要一些帮助。如果您在我的代码中输入一个目录,它将进入该目录中的每个文件夹并获取每个文件。通过这种方式,我通过使用代码绕过了“AccessDeniedException”,但是如果目录是一个包含大量数据和文件夹(例如:C:/)的目录,则需要花费大量的时间

我真的不知道如何使用多线程,在互联网上也找不到任何帮助。有没有办法通过多线程使代码运行得更快?或者可以要求代码使用更多内存或内核吗?我真的不知道,我需要你的建议

在每个子目录的每个文件中输入的代码:

public static List<string> Files = new List<string>();
public static List<string> Exceptions = new List<string>();

public MainWindow()
{
    InitializeComponent();
}

private static void GetFilesRecursively(string Directory)
{
    try
    {
         foreach (string A in Directory.GetDirectories(Directory))
             GetFilesRecursively(A);

         foreach (string B in Directory.GetFiles(Directory))
             AddtoList(B);

    } catch (System.Exception ex) { Exceptions.Add(ex.ToString()); }
}

private static void AddtoList(string Result)
{
    Files.Add(Result);
}

private void Btn_Click(object sender, RoutedEventArgs e)
{
    GetFilesRecursively(Textbox1.Text);
    
    foreach(string C in Files)
       Textbox2.Text += $"{C} \n";
}
公共静态列表文件=新列表();
公共静态列表异常=新列表();
公共主窗口()
{
初始化组件();
}
私有静态void getfiles递归(字符串目录)
{
尝试
{
foreach(Directory.GetDirectories(Directory))中的字符串A)
递归地获取文件(A);
foreach(Directory.GetFiles(Directory)中的字符串B)
AddtoList(B);
}catch(System.Exception ex){Exceptions.Add(ex.ToString());}
}
私有静态void AddtoList(字符串结果)
{
文件。添加(结果);
}
私有无效Btn_单击(对象发送方,路由目标)
{
递归地获取文件(Textbox1.Text);
foreach(文件中的字符串C)
Textbox2.Text+=$“{C}\n”;
}

您不需要递归来避免无法访问的文件。您可以使用接受参数并设置为
true
的重载:

var options=new EnumerationOptions 
            {
                IgnoreInaccessible=true,
                RecurseSubdirectories=true
            };
var files=Directory.EnumerateFiles(somePath,"*",options);
附加文件路径的循环也非常昂贵。它不仅在每次迭代中创建一个新的临时字符串,还强制用户界面重画。通过创建单个字符串(例如使用
string.Join
StringBuilder
),可以提高速度和内存使用率(由于垃圾收集也会影响性能):

var text=String.Join("\n",files);
Textbox2.Text=text;
String.Join
在内部使用StringBuilder,其内部缓冲区在每次满时都会重新分配。必须对上一个缓冲区进行垃圾收集。Once甚至可以通过使用具有特定容量的
StringBuilder
来避免这种情况。即使是粗略估计也可以显著减少再分配:

var builder=new StringBuilder(4096);
foreach(var file in files)
{
    builder.AppendLine(file);
}
  • 创建一个类,这样您就可以添加一个私有字段来计算directroy的深度
  • TaskSource
    属性添加到类中,并
    wait
    仅当深度超出限制时生成的
    Task
    ,并触发事件,以便您的UI可以挂接到操作并询问用户
  • 如果用户取消,则任务失败;如果用户确认,则继续
  • 一些逻辑代码

    public class FileLocator
    {
        public FileLocator(int maxDeep = 6){  
           _maxDeep = maxDeep; 
           this.TaskSource = new TaskSource();
           this.ConfirmTask  = this.TaskSource.Task;
        }
        private int _maxDeep;
        private int _deep;
    
        public event Action<FileLocator> OnReachMaxDeep;
    
        public Task ConfirmTask ;
        public TaskSource TaskSource {get;}
    
        public Task<List<string>> GetFilesRecursivelyAsync()
        {
           var result = new List<string>();
            foreach(xxxxxxx)
            {
                
                xxxxxxxxxxxxxx;
               this._deep +=1;
               if(_deep == _maxDeep)
               {  OnRichMaxDeep?.Invoke(this); }
               if(_deep >= _maxDeep)
               {
                  try{
                  await ConfirmTask;
                  continue;
                 }
                 catch{
                   return result;
    
                }
               }
            }
        }
    
    }
    

    扫描你的整个硬盘需要时间,不管你怎么做。即使是WinDirStat这样的应用程序也需要很长的时间才能完成。异常包含多少项?让异常发生是最后的手段,特别是当您谈论性能时。相反,您必须防止异常,例如在尝试访问文件夹之前检查文件夹权限。您的代码的用途是什么?要从您有权访问的目录及其子目录中获取文件列表,或者如果您也获得了异常,这是否重要?通过将搜索选项AllDirectories传递到GetFiles调用中,您可以调用目录上的GetFiles并包括子目录。在开始之前,您真的需要完整文件夹的结果吗?例如,如果我想到一个可视化的树,它就足以加载扩展的节点(按需)。@AsPas:在大多数情况下,读取文件系统时CPU不是你的问题。而文件系统往往会变得更慢,因为并行访问的进程越多。
    var locator = new FileLocator();
    
    locator.OnReachMaxDeep += (x)=> {  var result =  UI.Confirm();  if(result){ x.TaskSource.SetResult(); else{  x.TaskSource.SetException(new Exception())   } }  }
    
    
    var result = await locator.GetFilesRecursivelyAsync("C:");