我为我的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个单词。
答案 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();
}
结果:
PS:请注意,并非使用Parallel.For