protobuf-net 子消息未正确读取

Posted

技术标签:

【中文标题】protobuf-net 子消息未正确读取【英文标题】:protobuf-net Sub-message not read correctly 【发布时间】:2013-09-06 05:25:28 【问题描述】:

我目前正在测试 protobuf-net(最新版本),但在反序列化时间歇性地出现“子消息未正确读取”异常。到目前为止,还没有明显的模式可以重现此错误,并且数据始终相同。

我用谷歌搜索了这个错误,到目前为止人们只在处理大数据 (>20MB) 时才报告这个错误,我没有这样做。

谁能指出这是否是一个错误(如果是,任何可能的解决方案来修复/规避这个问题?),还是我错过了一些步骤?以下是我正在使用的代码:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

using ProtoBuf;

namespace ConsoleApplication1

    class Program
    
        static void Main(string[] args)
        
            const string message = "Cycle 0: 1:N2 ms - avg: 2:N2 ms - min: 3:N2 - max: 4:N2";
            const int loop = 1000;

            var counter = new Stopwatch();
            var average = 0d;
            var min = double.MaxValue;
            var max = double.MinValue;

            for (int i = 0;; i++)
            
                var classThree = Create();

                counter.Reset();
                counter.Start();

                Parallel.For(0, loop, j =>
                
                    using (var ms = new MemoryStream())
                    
                        Serializer.Serialize(ms, classThree);
                        using (var ms2 = new MemoryStream(ms.ToArray()))
                        
                            var des = Serializer.Deserialize<ClassThree>(ms2);
                            var aaa = des;
                        
                    
                );

                counter.Stop();

                var elapsed = counter.Elapsed.TotalMilliseconds;
                average += elapsed;
                min = Math.Min(min, elapsed);
                max = Math.Max(max, elapsed);
                var currentAverage = average / (i + 1);

                Console.Clear();
                Console.WriteLine(message, i, elapsed, currentAverage, min, max);

                Thread.Sleep(0);
            
        

        private static ClassThree Create()
        
            var classOne = new ClassSix()
            
                // properties
                p_i1 = -123,
                p_i2 = 456,
                p_l1 = -456,
                p_l2 = 123,
                p_s = "str",
                p_f = 12.34f,
                p_d = 56.78d,
                p_bl = true,
                p_dt = DateTime.Now.AddMonths(-1),
                p_m = 90.12m,
                p_b1 = 12,
                p_b2 = -34,
                p_c = 'c',
                p_s1 = -21,
                p_s2 = 43,
                p_ts = new TimeSpan(12, 34, 56),
                p_id = Guid.NewGuid(),
                p_uri = new Uri("http://www.google.com"),
                p_ba = new[]  (byte)1, (byte)3, (byte)2 ,
                p_t = typeof(ClassTwo),
                p_sa = new[]  "aaa", "bbb", "ccc" ,
                p_ia = new[]  7, 4, 9 ,
                p_e1 = EnumOne.Three,
                p_e2 = EnumTwo.One | EnumTwo.Two,
                p_list = new List<ClassFive>(new[]
                
                    new ClassFive()
                    
                        i = 1,
                        s = "1"
                    ,
                    new ClassFive()
                    
                        i = 2,
                        s = "2"
                    
                ),
                // fields
                f_i1 = -123,
                f_i2 = 456,
                f_l1 = -456,
                f_l2 = 123,
                f_s = "str",
                f_f = 12.34f,
                f_d = 56.78d,
                f_bl = true,
                f_dt = DateTime.Now.AddMonths(-1),
                f_m = 90.12m,
                f_b1 = 12,
                f_b2 = -34,
                f_c = 'c',
                f_s1 = -21,
                f_s2 = 43,
                f_ts = new TimeSpan(12, 34, 56),
                f_id = Guid.NewGuid(),
                f_uri = new Uri("http://www.google.com"),
                f_ba = new[]  (byte)1, (byte)3, (byte)2 ,
                f_t = typeof(ClassTwo),
                f_sa = new[]  "aaa", "bbb", "ccc" ,
                f_ia = new[]  7, 4, 9 ,
                f_e1 = EnumOne.Three,
                f_e2 = EnumTwo.One | EnumTwo.Two,
                f_list = new List<ClassFive>(new[]
                
                    new ClassFive()
                    
                        i = 1,
                        s = "1"
                    ,
                    new ClassFive()
                    
                        i = 2,
                        s = "2"
                    
                )
            ;
            var classThree = new ClassThree()
            
                ss = "333",
                one = classOne,
                two = classOne
            ;
            return classThree;
        
    

    public enum EnumOne
    
        One = 1,
        Two = 2,
        Three = 3
    

    [Flags]
    public enum EnumTwo
    
        One = 1,
        Two = 2,
        Three = 4
    

    [ProtoContract, ProtoInclude(51, typeof(ClassSix))]
    public class ClassOne
    
        // properties

        [ProtoMember(1)]
        public int p_i1  set; get; 

        [ProtoMember(2)]
        public uint p_i2  set; get; 

        [ProtoMember(3)]
        public long p_l1  set; get; 

        [ProtoMember(4)]
        public ulong p_l2  set; get; 

        [ProtoMember(5)]
        public string p_s  set; get; 

        [ProtoMember(6)]
        public float p_f  set; get; 

        [ProtoMember(7)]
        public double p_d  set; get; 

        [ProtoMember(8)]
        public bool p_bl  set; get; 

        [ProtoMember(9)]
        public DateTime p_dt  set; get; 

        [ProtoMember(10)]
        public decimal p_m  set; get; 

        [ProtoMember(11)]
        public byte p_b1  set; get; 

        [ProtoMember(12)]
        public sbyte p_b2  set; get; 

        [ProtoMember(13)]
        public char p_c  set; get; 

        [ProtoMember(14)]
        public short p_s1  set; get; 

        [ProtoMember(15)]
        public ushort p_s2  set; get; 

        [ProtoMember(16)]
        public TimeSpan p_ts  set; get; 

        [ProtoMember(17)]
        public Guid p_id  set; get; 

        [ProtoMember(18)]
        public Uri p_uri  set; get; 

        [ProtoMember(19)]
        public byte[] p_ba  set; get; 

        [ProtoMember(20)]
        public Type p_t  set; get; 

        [ProtoMember(21)]
        public string[] p_sa  set; get; 

        [ProtoMember(22)]
        public int[] p_ia  set; get; 

        [ProtoMember(23)]
        public EnumOne p_e1  set; get; 

        [ProtoMember(24)]
        public EnumTwo p_e2  set; get; 

        [ProtoMember(25)]
        public List<ClassFive> p_list  set; get; 

        // fields

        [ProtoMember(26)]
        public int f_i1 = 0;

        [ProtoMember(27)]
        public uint f_i2 = 0;

        [ProtoMember(28)]
        public long f_l1 = 0L;

        [ProtoMember(29)]
        public ulong f_l2 = 0UL;

        [ProtoMember(30)]
        public string f_s = string.Empty;

        [ProtoMember(31)]
        public float f_f = 0f;

        [ProtoMember(32)]
        public double f_d = 0d;

        [ProtoMember(33)]
        public bool f_bl = false;

        [ProtoMember(34)]
        public DateTime f_dt = DateTime.MinValue;

        [ProtoMember(35)]
        public decimal f_m = 0m;

        [ProtoMember(36)]
        public byte f_b1 = 0;

        [ProtoMember(37)]
        public sbyte f_b2 = 0;

        [ProtoMember(38)]
        public char f_c = (char)0;

        [ProtoMember(39)]
        public short f_s1 = 0;

        [ProtoMember(40)]
        public ushort f_s2 = 0;

        [ProtoMember(41)]
        public TimeSpan f_ts = TimeSpan.Zero;

        [ProtoMember(42)]
        public Guid f_id = Guid.Empty;

        [ProtoMember(43)]
        public Uri f_uri = null;

        [ProtoMember(44)]
        public byte[] f_ba = null;

        [ProtoMember(45)]
        public Type f_t = null;

        [ProtoMember(46)]
        public string[] f_sa = null;

        [ProtoMember(47)]
        public int[] f_ia = null;

        [ProtoMember(48)]
        public EnumOne f_e1 = 0;

        [ProtoMember(49)]
        public EnumTwo f_e2 = 0;

        [ProtoMember(50)]
        public List<ClassFive> f_list = null;
    

    [ProtoContract]
    public class ClassSix : ClassOne
    

    

    [ProtoContract]
    public class ClassTwo
    
    

    [ProtoContract]
    public interface IClass
    
        [ProtoMember(1)]
        string ss
        
            set;
            get;
        
        [ProtoMember(2)]
        ClassOne one
        
            set;
            get;
        
    

    [ProtoContract]
    public class ClassThree : IClass
    
        [ProtoMember(1)]
        public string ss  set; get; 

        [ProtoMember(2)]
        public ClassOne one  set; get; 

        [ProtoMember(3)]
        public ClassSix two  set; get; 
    

    [ProtoContract]
    public class ClassFour
    
        [ProtoMember(1)]
        public string ss  set; get; 

        [ProtoMember(2)]
        public ClassOne one  set; get; 
    

    [ProtoContract]
    public class ClassFive
    
        [ProtoMember(1)]
        public int i  set; get; 

        [ProtoMember(2)]
        public string s  set; get; 
    

【问题讨论】:

FWIW 我在 .Net 4.0 / PBuf v 2.0.0.640 上运行了大约 5000 次代码循环,没有出现问题:-( 是的,它是随机发生的。一旦我运行它超过2小时没有任何问题。然而在另一个例子中,我在几千个周期后得到了异常。 我会调查 - 现在不能做太多事情 (mobile.twitter.com/marcgravell/status/375875031538348032/photo/…) 顺便说一句 - 最新版本包括一些对象池 - 我首先要看的是那里的线程竞赛...... 根据@MarcGravell 的评论,我尝试使用 Parallel.For 而不是 for 循环,并且错误发生的频率更高。 【参考方案1】:

更新到 rev. 669,到目前为止还没有再次遇到错误。所以我现在报告此问题已修复。


【讨论】:

我认为 r668 解决了这个问题,但是是的:发现了一个错误 我看到的最新版本是r668。请问在哪里可以找到r669? 我只看到 r668 有没有 r669?

以上是关于protobuf-net 子消息未正确读取的主要内容,如果未能解决你的问题,请参考以下文章

使用 ProtoBuf-net 反序列化派生类型(字典)未正确设置对象字段

protobuf-net:不正确的线型反序列化 TimeSpan

序列化动态类型参数 Protobuf-net

protobuf-net:日期时间的编码

手工使用Protobuf-net工具来序列化对象

Python多处理:全局对象未正确复制给子对象