'List.Contains()'无限期地导致100%的CPU使用率

时间:2012-08-09 20:47:08

标签: c# asp.net .net

今天在一个项目上工作时,我在.NET中遇到了这种奇怪的行为。

我正在抓取文件名列表并将它们添加到对象中。但是,我需要根据已知的“坏”名称列表过滤传入的名称,这导致我这样做。 (我不是一个先进的C#编码器,仍然只是学习它。)但是,因为它导致 aspnet_wp.exe 进程无限期地以100%运行,我认为我正在做某事这种语言有问题。

这是我的参考代码:

List<string> localFiles = new List<string>(); 
// I was worried the object was causing the issue so dumbed it down to this with no changed.

string path = "//<file share>/<dir>/"; 
// As I commented below yes, it's slow when it works but it's clearly not working when using the if();

List<string> omitNames = new List<string>();
omitNames.Add("Thumbs.db"); 
// This is the only item in the list when it breaks also.

FileInfo[] localFileList = new DirectoryInfo(path).GetFiles();
foreach ( FileInfo item in localFileList )
{
    if(!omitNames.Contains(item.Name))
    {
        localFiles.Add(path + itemName);
    }
}

任何人都可以解释为什么这段代码作为无限循环运行?它看起来真的不应该。此外,我意识到使用List可能不是最好的方法。还有另一种方法可以干净利落地实施吗?

if(!){}注释omitNames可让代码正常运行。 (虽然显然没有过滤结果。)

更新:有人要求将其放入您可以在下方找到的控制台应用中。然而它完美无缺。另一件事是有人建议我尝试简单地将它与字符串进行比较。但是,如果改为这样,就会发生同样的事情:

if(item.Name != "Thumbs.db")
{
    localFiles.Add(path + itemName);
}

Console App(可行):

using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LoopKiller
{
class Program
{

    static void Main(string[] args)
    {

        List<string> omitNames = new List<string>();
        List<string> localFiles = new List<string>();

        omitNames.Add("Thumbs.db");

        FileInfo[] localFileList = new DirectoryInfo("c:/test/").GetFiles();

        foreach (FileInfo item in localFileList)
        {
            if (!omitNames.Contains(item.Name))
            {
                Console.WriteLine("Adding " + item.Name + " to localFiles.");
                localFiles.Add(item.Name);
                Console.WriteLine("Item added to localFiles.");
            }
        }

        foreach (string item in localFiles)
        {
            Console.WriteLine(item);
        }

        Console.ReadLine();

    }
}
}

3 个答案:

答案 0 :(得分:2)

这样更快吗?

foreach (string item in Directory.GetFiles("c:/test/", "*.*").Select(Path.GetFileName())
    {
        if (!omitNames.Contains(item))
        {
            Console.WriteLine("Adding " + item.Name + " to localFiles.");
            localFiles.Add(item.Name);
            Console.WriteLine("Item added to localFiles.");
        }
    }

答案 1 :(得分:1)

尝试使用Directory.EnumerateFiles。如果您只需要文件名作为字符串,那么为什么要获取整个FileInfo?我同意把它放在一个哈希集中。

Directory.EnumerateFiles

如果问题出在!omitNames.Contains(item.Name),仍然无济于事。那里有一些奇怪的事情,因为这应该是一个非常快速的电话。

对于161个文件的目录,它在2毫秒内运行,并正确地跳过这两个文件。

public void testFileFilter()
    {
        string path = @"c:\temp\";
        int pathLen = path.Length;
        string[] badNames = { "1692.pdf", "readme.htm" };
        List<string> goodNames = new List<string>();
        string fn;
        System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
        sw.Start();
        foreach(String fp in System.IO.Directory.EnumerateFiles(path))
        {
            //System.Diagnostics.Debug.WriteLine(fp);
            fn = fp.Substring(pathLen);
            //System.Diagnostics.Debug.WriteLine(fn);
            if(badNames.Contains(fn))
            {
                //fn = fp.Substring(pathLen);
            }
            else
            {
                goodNames.Add(fn);
            }
        }
        sw.Stop();
        System.Diagnostics.Debug.WriteLine(sw.ElapsedMilliseconds.ToString());
        System.Diagnostics.Debug.WriteLine(goodNames.Count());
    }    

答案 2 :(得分:0)

尝试以下方法:

List<string> localFiles = new List<string>();
// I was worried the object was causing the issue so dumbed it down to this with no changed.

string path = "//<file share>/<dir>/";
// As I commented below yes, it's slow when it works but it's clearly not working when using the if();

List<string> omitNames = new List<string>();
omitNames.Add("Thumbs.db");
// This is the only item in the list when it breaks also.

localFiles = (from files in new DirectoryInfo(path).GetFiles() where !omitNames.Contains(files.Name) select path + files.Name).ToList<string>();

至于你为什么遇到这个问题,我不知道。您可以尝试在循环和调试中设置断点。我发现调试可以解决大多数问题。例如,锁定获取文件信息。