Commit 2d4dee73 by mahaisong

fix:并行化,7秒执行完毕800W条记录,可以设置块大小,支持更高速读取1G 5G 10G 文件

parent db23a30e
...@@ -54,6 +54,7 @@ ...@@ -54,6 +54,7 @@
<Compile Include="ListModel.cs" /> <Compile Include="ListModel.cs" />
<Compile Include="Program.cs" /> <Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="V1.cs" />
<EmbeddedResource Include="Form1.resx"> <EmbeddedResource Include="Form1.resx">
<DependentUpon>Form1.cs</DependentUpon> <DependentUpon>Form1.cs</DependentUpon>
</EmbeddedResource> </EmbeddedResource>
......
...@@ -81,6 +81,7 @@ namespace CsvCount_ES ...@@ -81,6 +81,7 @@ namespace CsvCount_ES
{ {
Stopwatch st = new Stopwatch(); Stopwatch st = new Stopwatch();
st.Start(); st.Start();
int Btotal = 0;
if (!String.IsNullOrWhiteSpace(textBox1.Text)) if (!String.IsNullOrWhiteSpace(textBox1.Text))
{ {
...@@ -116,7 +117,7 @@ namespace CsvCount_ES ...@@ -116,7 +117,7 @@ namespace CsvCount_ES
setup: setup:
try try
{ {
#region 基本用法--820W行数据,439MB,转成字符串、split后,执行消耗14~15秒。 #region 基本用法--820W行数据,439MB,转成字符串、split后,执行消耗24~25秒。
////读取文件 ////读取文件
//FileInfo fi = new FileInfo(filepath); //FileInfo fi = new FileInfo(filepath);
//Int64 size = fi.Length;//byte长度 //Int64 size = fi.Length;//byte长度
...@@ -191,26 +192,39 @@ namespace CsvCount_ES ...@@ -191,26 +192,39 @@ namespace CsvCount_ES
#endregion #endregion
#region 并发用法:真正大文件时比StreamReader有用--820W行数据,439MB,转成字符串、split后,执行消耗7~8秒。 10K 1块。
//读取文件 //读取文件
FileInfo fi = new FileInfo(filepath); FileInfo fi = new FileInfo(filepath);
Int64 size = fi.Length;//byte长度 Int64 size = fi.Length;//byte长度
int length = 10240;//每次块大小 512000byte 500KB 这样1个G转2010次算完
int offset = 0; //10兆字节(mb)=10485760字节(b)
int length = 512000;//每次块大小 512000byte 500KB 这样1个G转2010次算完
//UTF-8编码中,一个英文字符等于一个字节,一个中文(含繁体)等于三个字节。 本次文件中主要是英文和数字,没有中文。所以要多少字就配多大块。 //UTF-8编码中,一个英文字符等于一个字节,一个中文(含繁体)等于三个字节。 本次文件中主要是英文和数字,没有中文。所以要多少字就配多大块。
//50千字节(kb)=51200字节(b)
//200千字节(kb)=204800字节(b)
Int64 portion = (Int64)Math.Ceiling(size * 1.0 / length); //分成多少块
string fp2 = @filepath; string fp2 = @filepath;
using (MemoryMappedFile mmf = MemoryMappedFile.CreateFromFile(fp2, FileMode.Open, "mapname")) //统一使用总文件大小的内存隐射对象
using (MemoryMappedFile mmf = MemoryMappedFile.CreateFromFile(fp2, FileMode.Open, "mapname", size))
{
//从零开始,每块单独并行处理。
Parallel.For(0,portion,(index,ParallelLoopState)=>
{
//块大小和 文件总大小-第几分区位置的剩余位置,取两者较小的
Int64 fileSize = Math.Min(length, size - length * index);
if (fileSize > 0)
{ {
using (var accessor = mmf.CreateViewAccessor(offset, size)) using (var accessor = mmf.CreateViewAccessor(length * index, fileSize, MemoryMappedFileAccess.Read))
{ {
List<string> list = new List<string>(); List<string> list = new List<string>();
//每隔100是1行 ////每隔100是1行
for (int i = 0; i < size; i += length) //for (int i = 0; i < fileSize; i += length)
{ //{
Int64 listkey = ADD(); //Int64 listkey = ADD();
...@@ -233,15 +247,15 @@ namespace CsvCount_ES ...@@ -233,15 +247,15 @@ namespace CsvCount_ES
//resultcount:读入 array 的结构数。 如果可用结构较少,则此值可能小于 count;如果到达访问器末尾,则为零。 //resultcount:读入 array 的结构数。 如果可用结构较少,则此值可能小于 count;如果到达访问器末尾,则为零。
#endregion #endregion
int resultcount = accessor.ReadArray(i, byteArray, 0, length); int resultcount = accessor.ReadArray(0, byteArray, 0, (int)fileSize);
//测试通过:\r\n \r 空格 \n(注意:\r 空格 \n 都算1个字符,\r\n算2个字符) //测试通过:\r\n \r 空格 \n(注意:\r 空格 \n 都算1个字符,\r\n算2个字符)
//规则:最后必须是\n结尾,cvs的换行都是\n结尾。 //规则:最后必须是\n结尾,cvs的换行都是\n结尾。
string str = System.Text.Encoding.Default.GetString(byteArray); string str = System.Text.Encoding.Default.GetString(byteArray);
int index = str.LastIndexOf('\n'); int index1 = str.LastIndexOf('\n');
string[] k = str.Split('\n'); string[] k = str.Split('\n');
string endstr = null; string endstr = null;
if (str.Length != index) if (str.Length != index1)
{ {
//不相等,最后一行不能Split分析。 //不相等,最后一行不能Split分析。
//spilt时,将最后一行保存起来,本次处理索引-1。 //spilt时,将最后一行保存起来,本次处理索引-1。
...@@ -277,12 +291,20 @@ namespace CsvCount_ES ...@@ -277,12 +291,20 @@ namespace CsvCount_ES
//头尾:另外保存 //头尾:另外保存
ListModel listmodel = new ListModel(k[0].Replace("\0", string.Empty).Replace("\r", string.Empty).Trim(), endstr); ListModel listmodel = new ListModel(k[0].Replace("\0", string.Empty).Replace("\r", string.Empty).Trim(), endstr);
listModelDic.TryAdd(listkey, listmodel); listModelDic.TryAdd(index, listmodel);
}
//}
}
//分区时,最后一个为0则忽略。
} }
});
} }
if (listModelDic.Count() > 0) if (listModelDic.Count() > 0)
...@@ -305,12 +327,11 @@ namespace CsvCount_ES ...@@ -305,12 +327,11 @@ namespace CsvCount_ES
else else
{ {
//头尾单独链式处理: 从1开始。第0行的begin 是列名称,不需要分析。 //头尾单独链式处理: 从1开始。第0行的begin 是列名称,不需要分析。
//注意这里是用i标识key,而key是从1开始的,i=2,i-1就等于1,即,key=1的值。同理。listModelDic.Count()+1为901,i为900时,计算899end和900的begin。 for (int i = 1; i < listModelDic.Count() ; i++)
for (int i = 2; i < listModelDic.Count() + 1; i++)
{ {
try try
{ {
count = count + 1;//记录计算了多少次,与分块对应(其实就是与listModelDic的key-1对应即代表完整) //count = count + 1;//记录计算了多少次,与分块对应(其实就是与listModelDic的key-1对应即代表完整)
string str = ""; string str = "";
if (!String.IsNullOrWhiteSpace(listModelDic[i - 1].End)) if (!String.IsNullOrWhiteSpace(listModelDic[i - 1].End))
...@@ -343,6 +364,7 @@ namespace CsvCount_ES ...@@ -343,6 +364,7 @@ namespace CsvCount_ES
} }
} }
#endregion
} }
catch (IOException ex) catch (IOException ex)
{ {
...@@ -366,13 +388,12 @@ namespace CsvCount_ES ...@@ -366,13 +388,12 @@ namespace CsvCount_ES
MessageBox.Show(ex.ToString()); MessageBox.Show(ex.ToString());
} }
#endregion #endregion
st.Stop(); st.Stop();
MessageBox.Show("运行时间:" + st.ElapsedMilliseconds.ToString()); MessageBox.Show("运行时间:" + st.ElapsedMilliseconds.ToString());
#region 完整性测试---使用时注释掉。 #region 完整性测试---使用时注释掉。 执行效率 5-6
try try
{ {
...@@ -408,18 +429,26 @@ namespace CsvCount_ES ...@@ -408,18 +429,26 @@ namespace CsvCount_ES
swtp.Stop(); swtp.Stop();
MessageBox.Show("完整性测试运行时间:" + swtp.ElapsedMilliseconds.ToString()); MessageBox.Show("完整性测试运行时间:" + swtp.ElapsedMilliseconds.ToString());
#endregion #endregion
//可能出现重复,这里的条数与日志文件的条数可能不同。
foreach (var item in BtotalCountDic)
{
Btotal = Btotal + item.Value;
}
//全比较 //全比较
var dz1 = BtotalCountDic.Except(totalCountDic); var dz1 = BtotalCountDic.Except(totalCountDic);
//key比较 //key比较
var dz2 = BtotalCountDic.Keys.Except(totalCountDic.Keys); var dz2 = BtotalCountDic.Keys.Except(totalCountDic.Keys);
if (null == dz1.First() && null == dz2.First()) if (dz1.Count() == 0 && dz2.Count() == 0)
{ {
//两个方式结果一致。 MessageBox.Show("两个方式结果一致");
} }
else else
{ {
MessageBox.Show("完整性测试报错" ); MessageBox.Show("完整性测试报错");
} }
} }
catch (Exception exe1) catch (Exception exe1)
...@@ -445,6 +474,21 @@ namespace CsvCount_ES ...@@ -445,6 +474,21 @@ namespace CsvCount_ES
button1.Enabled = true; button1.Enabled = true;
int total = 0;
foreach (var item in totalCountDic)
{
total = total+ item.Value;
}
if (total == Btotal)
{
MessageBox.Show("正确:点击数和为总条数");
}
else
{
MessageBox.Show("错误:点击数和不等于总条数");
}
MessageBox.Show("结果行数:" + count.ToString()); MessageBox.Show("结果行数:" + count.ToString());
errorCount = 0; errorCount = 0;
......
...@@ -12,7 +12,9 @@ C:\Users\admin\Desktop\CsvCount_ES\CsvCount_ES\obj\Debug\CsvCount_ES.exe ...@@ -12,7 +12,9 @@ C:\Users\admin\Desktop\CsvCount_ES\CsvCount_ES\obj\Debug\CsvCount_ES.exe
C:\Users\admin\Desktop\CsvCount_ES\CsvCount_ES\obj\Debug\CsvCount_ES.pdb C:\Users\admin\Desktop\CsvCount_ES\CsvCount_ES\obj\Debug\CsvCount_ES.pdb
C:\Users\admin\Desktop\CsvCount_ES\CsvCount_ES\bin\Debug\CsvCount_ES.exe C:\Users\admin\Desktop\CsvCount_ES\CsvCount_ES\bin\Debug\CsvCount_ES.exe
C:\Users\admin\Desktop\CsvCount_ES\CsvCount_ES\bin\Debug\CsvCount_ES.pdb C:\Users\admin\Desktop\CsvCount_ES\CsvCount_ES\bin\Debug\CsvCount_ES.pdb
C:\Users\admin\Desktop\CsvCount_ES\CsvCount_ES\obj\Debug\CsvCount_ES.csprojResolveAssemblyReference.cache
C:\Users\admin\Desktop\CsvCount_ES\CsvCount_ES\obj\Debug\CsvCount_ES.Form1.resources C:\Users\admin\Desktop\CsvCount_ES\CsvCount_ES\obj\Debug\CsvCount_ES.Form1.resources
C:\Users\admin\Desktop\CsvCount_ES\CsvCount_ES\obj\Debug\CsvCount_ES.Properties.Resources.resources C:\Users\admin\Desktop\CsvCount_ES\CsvCount_ES\obj\Debug\CsvCount_ES.Properties.Resources.resources
C:\Users\admin\Desktop\CsvCount_ES\CsvCount_ES\obj\Debug\CsvCount_ES.csproj.GenerateResource.Cache C:\Users\admin\Desktop\CsvCount_ES\CsvCount_ES\obj\Debug\CsvCount_ES.csproj.GenerateResource.Cache
D:\smallproject\6.CsvCount_ES\CsvCount_ES\bin\Debug\CsvCount_ES.exe.config
D:\smallproject\6.CsvCount_ES\CsvCount_ES\obj\Debug\CsvCount_ES.exe
D:\smallproject\6.CsvCount_ES\CsvCount_ES\obj\Debug\CsvCount_ES.pdb
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment