其实我是标题党,这篇文章并不是什么高端的优化教程,而是一个小菜鸡在生活中遇到的一个真实问题。
最近在一个项目,项目中有一个需求是这样的,从文本文件中读取若干数据,这些数据是一条条通过UDP接收的数据包,每个包长度是1046个字节,其中第a,b,c个字节(连续的)代表一个标识码,UDP是由6个IP发出的,因为当初接收数据时,发送端已经运行了一段时间,所以表示码是从某一个特别大的值开始的,博主的任务是把其中的标识码改成从0开始,每次加2.。
数据包可能出现错乱,比如连续出现了5个标识码为0016A5的数据包,突然出现了几个标识码为0016A7的数据包,再出现1个标识码为0016A5的数据包。要保证那个6个标识码为0016A5的全部被修改。
博主面对是一个大于100MB的文件,读取出来大约有125000条数据,如果6个ip为一组,那就是近似20833组数据。
博主的思路是这样的,用两层循环,外层循环 循环 125000/6次 内层循环理论循环125000次,设置一个变量,记录已经修改的个数,每次找到一个符合条件的数据包,变量+1,如果,已经找到6了 ,则跳出内层循环,变量清零。
//总共进行的比较操作次数 测试用
//long CompareCount = 0;
//long CompareCount2 = 0;
int mm = datas[0].buffBytes.Length;
int count = datas.Count;
byte[] line1start = new byte[] {byte.Parse("0"),datas[0].buffBytes[10], datas[0].buffBytes[11], datas[0].buffBytes[12] };
int intline1start = BitConvertHelper.ExtractToInt(line1start, 0);
byte[] line2start = new byte[] {byte.Parse("0"), datas[0].buffBytes[526], datas[0].buffBytes[527],datas[0].buffBytes[528]};
int intlin2start = BitConvertHelper.ExtractToInt(line2start, 0);
//K等于6时跳出 减少循环次数
int k = 0;
//数据是连续的 还是断了
bool _isCut = false;
//测试用 进入的时间
Console.WriteLine("开始的时间 " + DateTime.Now.ToString());
//
for (int i = 0; i < count/6; i++)
{
byte[] line1Bytes = BitConverter.GetBytes(line1);
BitConvertHelper.ReverseBytes(line1Bytes);
byte[] line2Bytes = BitConverter.GetBytes(line2);
BitConvertHelper.ReverseBytes(line2Bytes);
for (int j = 0; j < count; j++)
{
//CompareCount++;//测试用、
if (datas[j].buffBytes[10] == line1start[1] && datas[j].buffBytes[11] == line1start[2] &&
datas[j].buffBytes[12] == line1start[3])
//if (datas[j].lineOne == intline1start)
{
for (int l = 0; l < 3; l++)
{
datas[j].buffBytes[10 + l] = line1Bytes[l + 1];
datas[j].buffBytes[526 + l] = line2Bytes[l + 1];
}
k = k + 1;
datas[j].lineOne = line1;
}
if (k == 6)
{
//_isCut = false;
//一组6个数据更改 完毕 进入下一组
//CompareCount2++;
break;
}
}
k = 0;
line1=line1+2;
line2=line2+2;
intline1start = intline1start + 2;
intlin2start=intlin2start+2;
line1start =
BitConvertHelper.ReverseBytes(BitConverter.GetBytes(intline1start));
line2start =
BitConvertHelper.ReverseBytes(BitConverter.GetBytes(intline1start));
}
//测试用 结束的时间
Console.WriteLine("结束的时间 "+DateTime.Now.ToString());
//
//Console.WriteLine(CompareCount+" "+CompareCount2);
结果效率惨不忍睹,博主从没等到程序运行完成!
效率太差了!。
博主又对它进行了一些优化,比如增加一个变量,记录已经改变过得,连续的UDP包数量,这样内层循环就不用每次都从第0个开始了,但是并没有什么鸟用!!
public class Data
{
public byte[] buffBytes=new byte[1046];
public byte[] LineOne=new byte[3];
public int lineOne = 0;
}
在第一读取时,就把表示位算出来,比较时只需要比较一次。
//if (datas[j].buffBytes[10] == line1start[1] && datas[j].buffBytes[11] == line1start[2] &&
// datas[j].buffBytes[12] == line1start[3])
if (datas[j].lineOne == intline1start)
{
for (int l = 0; l < 3; l++)
{
datas[j].buffBytes[10 + l] = line1Bytes[l + 1];
datas[j].buffBytes[526 + l] = line2Bytes[l + 1];
}
k = k + 1;
datas[j].lineOne = line1;
}
if (k == 6)
{
//_isCut = false;
//一组6个数据更改 完毕 进入下一组
//CompareCount2++;
break;
}
结果博主活着等到了程序跑完的那一天~~
经检查数据都进行了修改,任务目的已经达到,但是1分钟还是太慢了。。。。
博主不知道是不是用字典会更快一点, 如果各位大大能提点意见 博主不胜感激!!后来测试直接比较3位字节 耗时2分钟 也就是说我节约了1分钟
后来 我把代码改成先按照IP分组,再每组同时修改!!这里应该考虑一下 丢线的问题
List<DataBuffer> datasList=new List<DataBuffer>();
datasList = DataReader(path);
Console.WriteLine("开始的时间 " + DateTime.Now.ToString());
var q = from data1 in datasList group data1 by data1.Bytes[9];
//Parallel.ForEach(q,d =>);
List<List<DataBuffer>> datalistsList = new List<List<DataBuffer>>();
foreach (var g in q)
{
List<DataBuffer> datassList = new List<DataBuffer>();
foreach (var b in g)
{
datassList.Add(b);
}
datalistsList.Add(datassList);
}
for (int i = 0; i < datalistsList[0].Count; i++)
{
Parallel.ForEach(datalistsList, d => d[i].LineOne = d[i].LineOne - 6135);
}
Console.WriteLine(datasList[datasList.Count-1].LineOne);
for (int i = 0; i < datasList.Count; i++)
{
byte[] line1Bytes =BitConvertHelper.ReverseBytes( BitConverter.GetBytes(datasList[i].LineOne));
byte[] line2Bytes =BitConvertHelper.ReverseBytes( BitConverter.GetBytes(datasList[i].LineOne + 1));
for (int l = 0; l < 3; l++)
{
datasList[i].Bytes[10 + l] = line1Bytes[l + 1];
datasList[i].Bytes[526 + l] = line2Bytes[l + 1];
}
}