我读取一个文件并一次解析其字节 5 个。第一个字节是标头,最后 4 个字节表示数据。(第一个包总是"Velocidad",所以不要担心 UltimoRD 为空。该文件约为 400 KB。
性能非常慢。我尝试使用数组,列表和IEnumerable,但我总是得到相同的,缓慢的结果。如何改进运行时?
public void Analizar(IEnumerable<byte> bytes)
{
var listado = new List<AnalisisResumenDiarioGenerico>();
while (bytes.Any())
{
var take = bytes.Take(5);
listado.Add(ObtenerPaquete(take));
bytes = bytes.Skip(5);
}
//InsertInDB(listado);
}
private AnalisisResumenDiarioGenerico ObtenerPaquete(IEnumerable<byte> take)
{
var tipo = take.First();
AnalisisResumenDiarioGenerico retorno;
switch (tipo)
{
case 241:
retorno = new Velocidad(new TimeSpan(take.ToArray()[1], take.ToArray()[2], take.ToArray()[3]), take.ToArray()[4]);
break;
case 242:
retorno = new Chofer(UltimoRD.fecha, BitConverter.ToInt32(take.ToArray(),1));
break;
case 243:
retorno = new Odometro(UltimoRD.fecha, BitConverter.ToInt32(take.ToArray(), 1));
break;
default: //should never get here
throw new FormatException();
}
UltimoRD = retorno;
return retorno;
}
尝试这样的事情:
public void Analizar(IEnumerable<byte> bytes)
{
var listado = new List<AnalisisResumenDiarioGenerico>();
using (var e = bytes.GetEnumerator())
{
var arr = new byte[5];
var posModFive = 0;
while (e.MoveNext())
{
arr[posModFive] = e.Current;
posModFive++;
if (posModFive == 5)
{
listado.Add(ObtenerPaquete(arr));
posModFive = 0;
}
}
if (posModFive != 0) { /* Hey, 5 did not divide the total length! */ }
}
//InsertInDB(listado);
}
你自己的代码的问题在于它本质上是这样做的:
bytes.Any();
bytes.Take(5).First();
bytes.Take(5).ToArray();
bytes.Skip(5).Any();
bytes.Skip(5).Take(5).First();
bytes.Skip(5).Take(5).ToArray();
bytes.Skip(5).Skip(5).Any();
bytes.Skip(5).Skip(5).Take(5).First();
bytes.Skip(5).Skip(5).Take(5).ToArray();
bytes.Skip(5).Skip(5).Skip(5).Any();
bytes.Skip(5).Skip(5).Skip(5).Take(5).First();
bytes.Skip(5).Skip(5).Skip(5).Take(5).ToArray();
...
因此,相同的IEnumerable<>
从一开始就被迭代了很多次。虽然Take
和Skip
是"懒惰"的,但Any
、First
和ToArray
必须真正"拉"出一些东西。它通过越来越多的Skip
处理程序(Take
在我的框架版本中System.Linq.Enumerable+<TakeIterator>d__3a`1[System.Byte]
; Take
可能yield return
循环)。
查尔斯·马格(Charles Mager)在对GazTheDestroyer的回答的评论中提到了画家施莱米尔(Schlemiel the Painter),这是高度相关的。
你的罪魁祸首可能是:
bytes = bytes.Skip(5);
每次通过循环时,您都会重新分配创建新列表。
只需保留原始列表并迭代到最后即可。
解决方案是使用BynaryReader。
public void Analizar(byte[] bytes)
{
BinaryReader bin = new BinaryReader(new MemoryStream(bytes));
var listado = new List<AnalisisResumenDiarioGenerico>();
while (true)
{
var take = bin.ReadBytes(5);
if (take.Count() == 0) break;
listado.Add(ObtenerPaquete(take));
}
Insertar(listado);
}
private AnalisisResumenDiarioGenerico ObtenerPaquete(IEnumerable<byte> take)
{
var tipo = take.First();
var data = take.ToArray();
AnalisisResumenDiarioGenerico retorno;
switch (tipo)
{
case 241:
retorno = new Velocidad(new TimeSpan(data[1], data[2], data[3]),data[4]);
break;
case 242:
retorno = new Chofer(UltimoRD.fecha, BitConverter.ToInt32(data,1));
break;
case 243:
retorno = new Odometro(UltimoRD.fecha, BitConverter.ToInt32(data, 1));
break;
default: //nunca debería llegar acá
throw new FormatException();
}
UltimoRD = retorno;
return retorno;
}
这需要 ~ 5 秒才能完成。