@
wuxqing @
billlee @
ncisoft @
batman2010 @
Andiry @
yangff 首先感谢各位的回复。
我的操作系统是 Win7 x64,CPU I5-4430主频3G,内存16GB,普通机械硬盘,开发环境是VS2013+C#;
经过一夜优化调试,现总结给大家,一个5G 文件,扫描统计后的结果如下:
x64编译:
每200MB扫描耗时0.85秒(不包括IO时间)
总耗时23.37秒(包括IO时间)
x86编译:
每200MB扫描耗时0.58秒(不包括IO时间)
总耗时16.66秒(包括IO时间)
优化主要将C#的数组改为指针去统计,绕过托管内存的消耗。
当中试过并行计算,使用的是.NET的并行类,但扫描时间比 for 循环稍长。
备注:每次缓存的数据大小和扫描时间成正比增长,所以不考虑是否全部载入内存。
源代码如下:
unsafe static class Analyzing
{
public static int[] Count(Stream stream)
{
byte[] buffer = new byte[204800000];
int read = 1;
// 用于保存统计数据的内存。
int* count = (int*)Marshal.AllocHGlobal(sizeof(int) * 256);
// 用0填充内存;
for (int i = 0; i < 256; i++)
{
count[i] = 0;
}
// 记录工作开始的时间。
DateTime begin = DateTime.Now;
// 循环读取数据到内存;
while (read > 0)
{
read = stream.Read(buffer, 0, buffer.Length);
if (read == 0) break;
// 记录扫描开始的时间。
DateTime start = DateTime.Now;
// 扫描内存的数据,并进行统计;
// count为int类型,256大小的内存区域;
// count的索引位置(0-255),代表字节0-255;
// count的索引内容,代表字节出现的频率。
for (int i = 0; i < read; i++)
{
count[buffer[i]]++;
}
// 输出扫描耗费的时间。
Console.WriteLine((DateTime.Now - start).TotalSeconds);
}
Marshal.FreeHGlobal((IntPtr)count);
// 输出工作耗费的时间。
Console.WriteLine((DateTime.Now - begin).TotalSeconds);
Console.ReadKey();
// 将非托管内存转换为托管数组,并返回该结果。
int[] result = new int[256];
Marshal.Copy((IntPtr)count, result, 0, result.Length);
return result;
}
}