改进IEnumerable <byte>解析性能

时间:2015-04-23 15:05:04

标签: c# performance linq

我读取一个文件并一次解析其字节5。第一个字节是标题,最后4个字节表示数据。 (第一个包总是&#34; Velocidad&#34;,所以不要担心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;
}

3 个答案:

答案 0 :(得分:2)

尝试这样的事情:

  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从头开始迭代很多次。虽然SkipAny是“懒惰”,但FirstToArraySkip必须实际“拉出”某些内容。在我的框架版本中,Take处理程序越来越多(System.Linq.Enumerable+<TakeIterator>d__3a`1[System.Byte]Take; yield return在循环中可能是 <script type="text/javascript"> function func_code() { var codes = null; var code_arr = null; var j = null; var i = null; codes = "100000,100004,100007,100009,100012"; code_arr = codes.split(','); var len = code_arr.length; for (j = 0; j <= len; j++) { for (i = code_arr[j]; i <= code_arr[j + 1]; i++) { setTimeout(function () { change_number(i) }, 2000); ******wait here for 2 seconds******* } } // document.getElementById('counter').innerHTML = 5000000; } function change_number(i) { document.getElementById('counter').innerHTML = i; } </script> <label id="counter">123</label> )。

Charles Mager在对GazTheDestroyer的答案的评论中提及Schlemiel the Painter是非常相关的。

答案 1 :(得分:1)

你的罪魁祸首可能是:

bytes = bytes.Skip(5);

您每次通过循环重新分配创建新列表。

保留原始列表并迭代到最后。

答案 2 :(得分:0)

解决方案是使用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秒钟才能完成。