提高 IE可<byte>数值解析性能



我读取一个文件并一次解析其字节 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<>从一开始就被迭代了很多次。虽然TakeSkip是"懒惰"的,但AnyFirstToArray必须真正"拉"出一些东西。它通过越来越多的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 秒才能完成。

最新更新