C# WPF 加速(线程)来自多个文件的总 FileInfo.Length

     2023-03-07     157

关键词:

【中文标题】C# WPF 加速(线程)来自多个文件的总 FileInfo.Length【英文标题】:C# WPF Speedup (Thread) Total FileInfo.Length from Multiple Files 【发布时间】:2014-11-13 15:04:59 【问题描述】:

我正在尝试加速由一个路径递归给出的所有文件夹中所有文件的总和计算。

假设我选择“E:\”作为文件夹。 我现在将以毫秒为单位通过“SafeFileEnumerator”将条目递归文件列表放入 IEnumerable(就像一个魅力)

现在我想从这个 Enumerable 中的所有文件中收集所有字节的总和。 现在我通过 foreach 循环它们并获取 FileInfo(oFileInfo.FullName).Length; - 对于每个文件。

这是有效的,但速度很慢 - 大约需要 30 秒。如果我通过 Windows 右键单击​​查找空间消耗 - Windows 资源管理器中所有选定文件夹的属性,我会在大约 6 秒内得到它们(在 ssd 上的 26 GB 数据中大约有 1600 个文件)

所以我的第一个想法是通过使用线程来加速收集,但我在这里没有得到任何加速..

没有线程的代码如下:

public static long fetchFolderSize(string Folder, CancellationTokenSource oCancelToken)

    long FolderSize = 0;

    IEnumerable<FileSystemInfo> aFiles = new SafeFileEnumerator(Folder, "*", SearchOption.AllDirectories);
    foreach (FileSystemInfo oFileInfo in aFiles)
    
        // check if we will cancel now
        if (oCancelToken.Token.IsCancellationRequested)
        
            throw new OperationCanceledException();
        

        try
        
            FolderSize += new FileInfo(oFileInfo.FullName).Length;
        
        catch (Exception oException)
        
            Debug.WriteLine(oException.Message);
        
    

    return FolderSize;

多线程代码如下:

public static long fetchFolderSize(string Folder, CancellationTokenSource oCancelToken)

    long FolderSize = 0;

    int iCountTasks = 0;

    IEnumerable<FileSystemInfo> aFiles = new SafeFileEnumerator(Folder, "*", SearchOption.AllDirectories);
    foreach (FileSystemInfo oFileInfo in aFiles)
    
        // check if we will cancel now
        if (oCancelToken.Token.IsCancellationRequested)
        
            throw new OperationCanceledException();
        

        if (iCountTasks < 10)
        
            iCountTasks++;
            Thread oThread = new Thread(delegate()
            
                try
                                            
                    FolderSize += new FileInfo(oFileInfo.FullName).Length;
                
                catch (Exception oException)
                
                    Debug.WriteLine(oException.Message);
                

                iCountTasks--;
            );
            oThread.Start();
            continue;
        

        try
        
            FolderSize += new FileInfo(oFileInfo.FullName).Length;
        
        catch (Exception oException)
        
            Debug.WriteLine(oException.Message);
        
    

    return FolderSize;

有人可以给我一个建议,我可以如何加快文件夹大小的计算过程吗?

问候

编辑 1(Parallel.Foreach 建议 - 请参阅 cmets)

public static long fetchFolderSize(string Folder, CancellationTokenSource oCancelToken)

    long FolderSize = 0;

    ParallelOptions oParallelOptions = new ParallelOptions();
    oParallelOptions.CancellationToken = oCancelToken.Token;
    oParallelOptions.MaxDegreeOfParallelism = System.Environment.ProcessorCount;

    IEnumerable<FileSystemInfo> aFiles = new SafeFileEnumerator(Folder, "*", SearchOption.AllDirectories).ToArray();

    Parallel.ForEach(aFiles, oParallelOptions, oFileInfo =>
    
        try
        
            FolderSize += new FileInfo(oFileInfo.FullName).Length;
        
        catch (Exception oException)
        
            Debug.WriteLine(oException.Message);
        
    );

    return FolderSize;

【问题讨论】:

【参考方案1】:

关于 SafeFileEnumerator 性能的旁注:

一旦获得 IEnumerable,并不意味着您获得了整个集合,因为它是惰性代理。试试下面这个 sn-p - 我相信你会看到性能差异(对不起,如果它没有编译 - 只是为了说明这个想法):

var tmp = new SafeFileEnumerator(Folder, "*", SearchOption.AllDirectories).ToArray(); // fetch all records explicitly to populate the array
IEnumerable<FileSystemInfo> aFiles = tmp;

现在你想要达到的实际结果。

    如果您只需要文件大小 - 最好请求有关文件系统的操作系统功能,而不是逐个查询文件。我将从 DirectoryInfo 类开始(例如参见 http://www.tutorialspoint.com/csharp/csharp_windows_file_system.htm)。 如果您需要计算每个文件的校验和,这绝对是一项缓慢的任务,因为您必须先加载每个文件(大量内存传输)。线程在这里不是助推器,因为它们会受到操作系统文件系统吞吐量的限制,而不是您的 CPU 能力。

【讨论】:

感谢您快速回答,但如果我尝试使用您的片段,我看不出速度有任何变化。文件列表以毫秒为单位收集。顺便说一句:我可以在 Windows 的性能管理器中看到硬盘的性能 - 当我的代码正在运行并收集文件/文件夹的总和时,我看不到任何“强”硬盘/固态硬盘访问:-/【参考方案2】:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.IO;

namespace ConsoleApplication3

    class Program
    
        static void Main(string[] args)
        
            long size = fetchFolderSize(@"C:\Test", new CancellationTokenSource());

        

            public static long fetchFolderSize(string Folder, CancellationTokenSource  oCancelToken)
    


            ParallelOptions po = new ParallelOptions();
            po.CancellationToken = oCancelToken.Token;
            po.MaxDegreeOfParallelism = System.Environment.ProcessorCount;

            long folderSize = 0;
            string[] files = Directory.GetFiles(Folder);

            Parallel.ForEach<string,long>(files,
                                            po,
                                            () => 0,
                                            (fileName, loop, fileSize) => 
                                            
                                                fileSize = new FileInfo(fileName).Length;
                                                po.CancellationToken.ThrowIfCancellationRequested();
                                                return fileSize;

                                            ,  
                                            (finalResult) => Interlocked.Add(ref folderSize, finalResult)
                                            );


            string[] subdirEntries = Directory.GetDirectories(Folder);

            Parallel.For<long>(0, subdirEntries.Length, () => 0, (i, loop, subtotal) =>
            
                if ((File.GetAttributes(subdirEntries[i]) & FileAttributes.ReparsePoint) !=
                      FileAttributes.ReparsePoint)
                    
                        subtotal += fetchFolderSize(subdirEntries[i], oCancelToken);
                        return subtotal;
                    
                    return 0;
                ,
                    (finalResult) => Interlocked.Add(ref folderSize, finalResult)
                );

            return folderSize ;
    
    


【讨论】:

递归并行任务 在调试模式之外执行速度测试我得到的结果相当于在大型目录上的 Windows 资源管理器。 感谢您的贡献。我刚刚测试了你的代码,但我有严重的问题:(如果我选择“E:/”作为起始文件夹来获取大小,我会从“Directory.GetDirectories(Folder)”中得到一个异常,因为它会(内部)尝试获取我无法访问的“系统卷信息”文件夹的文件夹信息。这就是为什么我切换到“SafeFileEnumerator”的原因。另一方面,我的测试总大小只有 64MB C:\users 文件夹,其中包含 33GB 数据:-/ 我没有调试你的代码,因为 Directory.GetDirectories(Folder);我不能使用(异常/系统目录)但我尝试将我的代码与您的 Parallel.Foreach 循环建议结合起来,该建议有效,但没有得到任何加速更改:-/

多线程任务更新 1 个进度条 - UI C# WPF

】多线程任务更新1个进度条-UIC#WPF【英文标题】:Multiplethreadstasksupdating1progressbar-UIC#WPF【发布时间】:2021-07-1619:30:51【问题描述】:我一直在四处寻找有类似问题的人,但没有找到任何东西。我正在使用WPFUI编写C#应用程序。要... 查看详情

C# WPF IsEnabled 使用多个绑定?

】C#WPFIsEnabled使用多个绑定?【英文标题】:C#WPFIsEnabledusingmultiplebindings?【发布时间】:2010-10-3100:48:06【问题描述】:我有一个WPFxaml文件,描述了GUI的一部分,我希望特定控件的启用/禁用依赖于其他两个控件。代码现在看起来... 查看详情

使用多线程c#创建多个文件

】使用多线程c#创建多个文件【英文标题】:createmultiplefilesusingmultiplethreadsc#【发布时间】:2020-01-1918:45:42【问题描述】:我正在创建控制台应用程序来模拟服务器。我使用多个线程一起创建多个病毒文件,以查看是否所有文件... 查看详情

在运行时动态创建多个 UI 元素 - C# WPF

】在运行时动态创建多个UI元素-C#WPF【英文标题】:CreatingmultipleUIElementsdynamicallyduringruntime-C#WPF【发布时间】:2015-10-0814:59:00【问题描述】:我对C#和WPF还很陌生,但我开始构建一个应用程序,它应该具有列出项目的功能和一些细... 查看详情

WPF 加速键,如 Visual Studio

】WPF加速键,如VisualStudio【英文标题】:WPFAcceleratorKeyslikeVisualStudio【发布时间】:2010-10-1608:49:30【问题描述】:我正在使用C#和WPF开发一个大型业务应用程序。我们的标准是在所有表单(保存、取消、搜索等)上包含用于按钮的... 查看详情

java示例代码_计算多个线程完成执行所需的总时间

java示例代码_计算多个线程完成执行所需的总时间 查看详情

在 C# 中,如何处理具有多个线程/任务但有条件的大型文本文件?

】在C#中,如何处理具有多个线程/任务但有条件的大型文本文件?【英文标题】:InC#,howdoIprocessalargetextfilewithmultiplethreads/tasks,butwithconditions?【发布时间】:2021-07-2805:45:44【问题描述】:我正在用C#编写一个文件处理程序。我有一... 查看详情

.NET WPF (C#) 我无法从另一个线程获取更改背景的按钮

】.NETWPF(C#)我无法从另一个线程获取更改背景的按钮【英文标题】:.NETWPF(C#)ICannotGetTheButtonToChangeBackgroundfromAnotherThread【发布时间】:2021-11-2408:34:53【问题描述】:尽管从UI线程实例化的线程中使用Dispatcher,但我似乎无法让按钮... 查看详情

ZipFile (System.IO.Compression)、c# (WPF) 的字符提取问题

...间】:2020-01-1413:42:11【问题描述】:我正在尝试提取包含多个文件的zip。某些文件的名称中包含“§”字符(“abc(§7)abc.txt”)。开箱时,System.IO.Compress 查看详情

C# .NET 5.0 Wpf UI 被另一个线程修改

】C#.NET5.0WpfUI被另一个线程修改【英文标题】:C#.NET5.0WpfUImodifiedbyanotherthread【发布时间】:2021-04-0618:31:35【问题描述】:我在从另一个线程更新WPFUI时遇到了一些麻烦。第二个线程是一个不断从StreamReader读取消息的循环。在这些... 查看详情

WPF C# Ninject 与 mainViewModel 和多个 viewmodel 问题

】WPFC#Ninject与mainViewModel和多个viewmodel问题【英文标题】:WPFC#NinjectwithamainViewModelandmultipleviewmodelproblem【发布时间】:2018-12-1118:35:00【问题描述】:在我的应用程序中实现ninject时遇到问题。我的应用程序包含一个MainView视图和视... 查看详情

C# WPF 文件创建

】C#WPF文件创建【英文标题】:C#WPFFilesCreation【发布时间】:2010-07-1316:19:07【问题描述】:如何使用C#WPF创建access2000-2003文件并在其中添加表、数据并对其执行查询?【问题讨论】:【参考方案1】:您可以像在任何其他C#.NET应用... 查看详情

C# WPF 想要将数据存储在一个类中,并在不同 wpf 窗口中的多个不同类中使用

】C#WPF想要将数据存储在一个类中,并在不同wpf窗口中的多个不同类中使用【英文标题】:C#WPFWanttostoredatainaclassanduseitinmultipledifferentclassesindifferentwpfwindows【发布时间】:2022-01-1902:28:48【问题描述】:我有3节课。第一个存储信息... 查看详情

处理来自多个进程的单个文件

...单个简单程序花费的时间太长,我希望它通过多个进程或线程来完成。每个线程/进程都应该从该单个文件中读取不同的数据(不同的行),并对它们的数据(行)进行一些操作并将它们放入数 查看详情

SQL Server CE:到同一个数据库(C#,WPF)的多个连接(2+ 应用程序)

】SQLServerCE:到同一个数据库(C#,WPF)的多个连接(2+应用程序)【英文标题】:SQLServerCE:multipleconnections(2+apps)tothesamedb(C#,WPF)【发布时间】:2015-10-0214:19:46【问题描述】:我的C#WPF应用程序使用SQLServerCE4数据库,一切正常。但是... 查看详情

同步处理来自多个线程的数据

】同步处理来自多个线程的数据【英文标题】:Processingdatafromseveralthreadsinsync【发布时间】:2015-12-2022:00:30【问题描述】:在使用多个线程时我是否需要担心同步问题?我正在编写一个代码,该代码计算不同麦克风通道之间的延... 查看详情

c#带有Highchart的WPF Webbrowser,来自外部源的Javascript不起作用“此页面上的脚本中发生错误”

】c#带有Highchart的WPFWebbrowser,来自外部源的Javascript不起作用“此页面上的脚本中发生错误”【英文标题】:c#WPFWebbrowserwithHighchart,Javascriptfromexternalsourcenotworking"Anerrorhasoccurredinthescriptonthispage"【发布时间】:2018-05-1813:56:01... 查看详情

C# - WPF - 从另一个线程上的另一个类更新 UI

】C#-WPF-从另一个线程上的另一个类更新UI【英文标题】:C#-WPF-UpdatingtheUIfromanotherclassonanotherThread【发布时间】:2020-10-1504:17:33【问题描述】:我浏览了互联网,发现了一个不错的解决方案,我将其合并到下面的代码中,但是它并... 查看详情