C# for循环进入0%cpu挂起

C# for循环进入0%cpu挂起,c#,.net,for-loop,clr,C#,.net,For Loop,Clr,我需要获取一个文件列表,将它们修剪到目录路径并返回一个不同的列表。在某些情况下,这可能会处理超过500万个文件 我遇到一个问题,由于无法确定的原因,核心进程在CPU使用率为0%时挂起 var filePaths = File.ReadAllLines("list_of_files.txt"); // ... blockSw.Restart(); int[] curCounter = new int[1]; Stopwatch groupSw = Stopwatch.StartNew(); Par

我需要获取一个文件列表,将它们修剪到目录路径并返回一个不同的列表。在某些情况下,这可能会处理超过500万个文件

我遇到一个问题,由于无法确定的原因,核心进程在CPU使用率为0%时挂起

var filePaths = File.ReadAllLines("list_of_files.txt");
// ...
blockSw.Restart();
int[] curCounter = new int[1];
Stopwatch groupSw = Stopwatch.StartNew();
Parallel.For(0, filePaths.LongLength, i =>
  {
    //Trim the filename, if it exists, off of every
    // entry that we read out of the input file
    filePaths[i] = (Path.GetDirectoryName(filePaths[i]));
    //This can be used to safely report status
    // little hack-y, though
    lock (curCounter)
    {
        curCounter[0]++;
        if (curCounter[0] % 100000 == 0)
        {
            Trace.WriteLine(curCounter[0].ToString() + " rows complete in "
                + groupSw.ElapsedMilliseconds
                + " ; total time: " + blockSw.ElapsedMilliseconds);
            groupSw.Restart();
        }
    }
  }
);
blockSw.Stop();
Trace.WriteLine("Completed path truncation in " + blockSw.ElapsedMilliseconds + "ms.");
输出结果如下所示:

100000 rows complete in 266 ; total time: 266
200000 rows complete in 239 ; total time: 507
300000 rows complete in 843 ; total time: 1351
400000 rows complete in 1058 ; total time: 2411
...
1100000 rows complete in 3480 ; total time: 11602
1200000 rows complete in 432 ; total time: 12036
1300000 rows complete in 342 ; total time: 12379
...
4800000 rows complete in 832 ; total time: 48617
4900000 rows complete in 377 ; total time: 48996
5000000 rows complete in 2841 ; total time: 51839
5100000 rows complete in 1285 ; total time: 53126
Completed path truncation in 148124ms.
注意最后两行。。。53秒完成所有操作,然后循环结束,我们坐下来等待约90秒。在TaskManager中查看进程时,我可以看到它在这段时间内处于0%CPU的空闲状态

关于这里发生了什么或者我在哪里寻找线索有什么线索吗

列出文件路径的输入文件约为400MB,在此过程中,TaskManager报告的内存大小约为900MB。在测试期间,有大量的可用物理RAM超过这个数量

去掉循环中的状态报告不会改变性能-在循环结束时,我们仍然会得到约90秒的CPU使用率挂起

对于标准的
for
循环,而不是
并行。for
,我也有同样的问题


更新/解决方案 多亏了克里斯、杰克和汉斯。克里斯的意见是他无法复制的,汉斯建议我打破一切,我才得以缩小问题的范围。进一步调试后,我发现实际问题是
Path.GetDirectoryName
是罪魁祸首。虽然它在几乎每个文件路径上都运行了0-15毫秒,但有几十条路径需要2分钟才能处理。我注意到这些路径中都包含~。我仍然不清楚它为什么不使用CPU就可以这样做,但这足以让我理解它是一个
路径
内部路径,唯一加速它的方法是重新实现
GetDirectoryName

作为distinct。
可能不会比执行所有操作和执行单个LINQ更快,但应该是内存更少

using (StreamReader sr = new StreamReader("TestFile.txt"))
{
   String line;
   String path;
   HashSet<string> paths = HashSet<string>(StringComparer.OrdinalIgnoreCase);
   // Read and process lines from the file until the end of
   // the file is reached.
   while ((line = sr.ReadLine()) != null)
   {
       Console.WriteLine(line);
       path = Path.GetDirectoryName(line);
       if(!String.IsNullOrEmpty(path)) paths.Add(path.Trim());
   }
}
使用(StreamReader sr=newstreamreader(“TestFile.txt”))
{
弦线;
字符串路径;
HashSet路径=HashSet(StringComparer.OrdinalIgnoreCase);
//读取并处理文件中的行,直到
//已到达该文件。
而((line=sr.ReadLine())!=null)
{
控制台写入线(行);
path=path.GetDirectoryName(行);
if(!String.IsNullOrEmpty(path))path.Add(path.Trim());
}
}

我无法在LINQPad中复制此内容。也许是追踪的问题?编辑:然而,我的文件只需要大约9600毫秒就可以完成(即使是一个有5150万行的400 MB文件)。不过,文件中的文件路径都是相同的,所以可能会有一些分支预测。但离你的53秒还差得远。EDITx2:或者更可能的情况是,考虑到并行循环,只有可用的系统资源
for
loop for me花费了约32秒的时间(虽然最后仍然不是随机延迟),你能连接一个调试器并找到它挂起的位置吗?这不是问这个问题的正确方式。发布代码的最简单版本。观察挂起时,使用Debug+breakall并向我们显示调用堆栈窗口内容的外观。启用非托管调试和Microsoft Symbol服务器。如果您在调用堆栈中看到奇怪的命名DLL,那么您已经找到了此挂起的主要来源。这并没有达到distinct list的规定要求。谢谢@Chris、@Jack和@Hans。由于Chris无法在不同的数据集上复制,以及Hans建议打破所有并确认它实际在做什么,我能够确认它实际上是一些长期运行的
Path.GetDirectoryName
调用。