单词快速计数

时间:2015-03-04 00:58:07

标签: c# asp.net performance optimization count

我为我的ASP.NET服务器实现了字数统计功能,我想知道这样做的最快方法是什么,因为我不确定使用简单的

text.AsParallel().Count(Char.IsWhiteSpace);

是最快的方法。由于此功能可能会在相对较长的文本墙上使用相当多,我希望它尽可能快,即使它意味着使用不安全的方法。

编辑:使用Rufus L代码以及我自己的不安全方法进行基准测试:

public static unsafe int CountWords(string s)
    {
        int count = 0;
        fixed (char* ps = s)
        {
            int len = s.Length;
            char* pc = ps;
            while (len-- > 0)
            {
                if (char.IsWhiteSpace(*pc++))
                {
                    count++;
                }
            }
        }
        return count;
    }
  

Split(null):415867个刻度中的681979个单词。

     

伯爵(WhiteSpace):147860蜱虫中的681978个单词。

     

AsParallel:401077个字数中的681978个单词。

     

不安全:在98139蜱中有681978个单词。

我仍然愿意接受任何更好的想法:)

EDIT2:

重写了这个功能,同时处理了多个空格:

public static unsafe int CountWords(string s)
    {
        int count = 0;
        fixed (char* ps = s)
        {
            int len = s.Length;
            bool inWord = false;
            char* pc = ps;
            while (len-- > 0)
            {
                if (char.IsWhiteSpace(*pc++))
                {
                    if (!inWord)
                    {
                        inWord = true;
                    }
                }
                else
                {
                    if (inWord)
                    {
                        inWord = false;
                        count++;
                    }
                }
                if (len == 0)
                {
                    if (inWord)
                    {
                        count++;
                    }
                }
            }
        }
        return count;
    }
  

Split(null):517055个刻度中的681979个单词。

     

伯爵(WhiteSpace):148952个蜱虫中的681978个单词。

     

AsParallel:410289个单词中的681978个单词。

     

不安全:114833个刻度中的660000个单词。

3 个答案:

答案 0 :(得分:2)

根据我的测试,这个速度要快4倍(但请参阅下面的更新,了解不同的结果):

wordCount = text.Split(null).Length;

这是测试,如果你想尝试一下。请注意,由于任务切换的成本,添加AsParallel()会降低我的计算机上的进程速度:

public static void Main()
{
    var text = File.ReadAllText("d:\\public\\temp\\temp.txt");
    int wordCount;
    var sw = new Stopwatch();

    sw.Start();
    wordCount = text.Split(null).Length;
    sw.Stop();

    Console.WriteLine("Split(null): {0} words in {1} ticks.", wordCount, 
        sw.ElapsedTicks);

    sw.Restart();
    wordCount = text.Count(Char.IsWhiteSpace);
    sw.Stop();

    Console.WriteLine("Count(WhiteSpace): {0} words in {1} ticks.", wordCount, 
        sw.ElapsedTicks);

    sw.Restart();
    wordCount = text.AsParallel().Count(Char.IsWhiteSpace);
    sw.Stop();

    Console.WriteLine("AsParallel: {0} words in {1} ticks.", wordCount, 
        sw.ElapsedTicks);
}

输出:

  

Split(null):629个刻度中的964个单词。

     

Count(WhiteSpace):2377个刻度中的963个单词。

     

AsParallel:208983年的963个单词。

<强>更新

使字符串MUCH更长(OP提到100个单词的100个)后,结果变得更加相似,Count(WhiteSpace)方法变得比Split(null)方法更快:

代码更改:

var text = File.ReadAllText("d:\\public\\temp\\temp.txt");
var textToSearch = new StringBuilder();
for (int i = 0; i < 500; i++) textToSearch.Append(text);
text = textToSearch.ToString();

输出:

  

Split(null):185135个刻度中的481501个单词。

     

Count(WhiteSpace):101373个刻度中的481500个单词。

     

AsParallel:336117个字数中的481500个单词。

答案 1 :(得分:1)

经过一些基准测试后,以下非语言代码在任何情况下都会产生最快的结果:500多个单词:

public static unsafe int CountWords(string s)
{
    int count = 0;
    fixed (char* ps = s)
    {
        int len = s.Length;
        bool inWord = false;
        char* pc = ps;
        while (len-- > 0)
        {
            if (char.IsWhiteSpace(*pc++))
            {
                if (!inWord)
                {
                    inWord = true;
                }
            }
            else
            {
                if (inWord)
                {
                    inWord = false;
                    count++;
                }
            }
            if (len == 0)
            {
                if (inWord)
                {
                    count++;
                }
            }
        }
    }
    return count;
}

答案 2 :(得分:0)

回答你的问题,方法AsParallel()非常快。但是存在更多选择,例如:

使用Regex:

string input = "text text text text";
string pattern = "(-)";

string[] substrings = Regex.Split(input, pattern);    // Split on hyphens
Console.WriteLine("Words: {0}", substrings.count());

但我重申,AsParallel()方法非常快。你可以做一个概念验证,找出哪个更好。在开头放置一个秒表(),在代码末尾放置另一个秒表()并将AsParallel运行时()与正则表达式进行比较,这样就会有一个更“精确”的答案。

更新

使用Parallel.For:

static void Main(string[] args)
        {
            string text = @"text text text text text text text text text text ";
            int count = 0;

            Console.WriteLine("Generating words, wait...");
            Parallel.For(0, 100000, i =>
            {
                text += @"text text text text text text text text text text ";
            });


            var sw = new Stopwatch();
            sw.Start();
            Parallel.For(0, text.Length, i =>
            {
                if (char.IsWhiteSpace(text[i]))
                    count++;
            });
            sw.Stop();

            Console.WriteLine("Words: {0} in {1} ticks", count, sw.ElapsedTicks);
            Console.ReadLine();
        }

结果:

enter image description here

  

PS:请注意,并非使用Parallel.For