Type structure and performance comparison test - Example heartbeat packet to encapsulate the network

1. Background

Continued articles in layman's language C # structure - Ethernet package heartbeat packets, for example , the use of poor performance structure, but also explains why. This article describes in detail the advantages and disadvantages in class to encapsulate the heartbeat packet network, the results greatly improved analytical performance.

2. heartbeat packets encapsulated Ethernet class advantages and disadvantages

2.1 Advantages

  • Direct new byte [], an array of bytes that is a direct instance class, and then write the initialization method or constructor directly passed in cache copy assignment;
  • You do not need boxing and unboxing;
  • Category is a reference type, a value without copying the image structure, the bottom layer is directly smart pointer;
  • Smart pointers to the same piece of memory, save memory space;
  • I can write a lot of convenient method in class, which is object-oriented, domain-oriented cornerstone for easy future expansion;

2.2 Disadvantages

  • Presence pile, stack somewhat less than the read performance (the PC now calculate speed quickly, substantially negligible);
  • Although the class also belong to a managed resource of GC, GC but when automatic recovery can not control, you need to implement the IDisposable interface, run out of the class, the class is manually released action;

How to use the actual performance class, we use test data to speak, we will put behind the performance of comparative data and structure testing.

3. Network-based heartbeat packet encapsulation

Here are all named became a byte array, including public byte [] type = new byte [1]; because if it is byte type type, I do not know how to release this value type, fear of causing problems such as memory leaks that time. Then the constructor function to copy the buffer buf each property class, is that simple.

    public class TcpHeartPacketClass: BaseDisposable
    {
        private bool _disposed; //表示是否已经被回收
        public TcpHeartPacketClass(byte[] buf)
        {
            Buffer.BlockCopy(buf, 0, head, 0, 4);
            type[0] = buf[4];
            Buffer.BlockCopy(buf, 4, length, 0, 2);
            Buffer.BlockCopy(buf, 6, Mac, 0, 6);
            Buffer.BlockCopy(buf, 12, data, 0, 104);
            Buffer.BlockCopy(buf, 116, tail, 0, 4);
        }
        protected override void Dispose(bool disposing)
        {
            if (!_disposed) //如果还没有被回收
            {
                if (disposing) //如果需要回收一些托管资源
                {
                    //TODO:回收托管资源,调用IDisposable的Dispose()方法就可以
                    
                }
                //TODO:回收非托管资源,把之设置为null,等待CLR调用析构函数的时候回收
                head = null;
                type = null;
                length = null;
                Mac = null;
                data = null;
                tail = null;

                _disposed = true;

            }
            base.Dispose(disposing);//再调用父类的垃圾回收逻辑
        }

        public byte[] head=new byte[4];

        public byte[] type=new byte[1];

        public byte[] length = new byte[2];

        public byte[] Mac = new byte[6];

        public byte[] data = new byte[104];//数据体

        public byte[] tail = new byte[4];
    }  

4. Implement IDisposable interface

Exhausted after class, to take the initiative to release the class, I release encapsulates a base class BaseDisposable. Refer to code notes, there do not understand can ask questions in the comments section, I will answer in detail.

    public class BaseDisposable : IDisposable
    {
        ~BaseDisposable()
        {
            //垃圾回收器将调用该方法,因此参数需要为false。
            Dispose(false);
        }

        /// <summary>
        /// 是否已经调用了 Dispose(bool disposing)方法。
        ///     应该定义成 private 的,这样可以使基类和子类互不影响。
        /// </summary>
        private bool disposed = false;

        /// <summary>
        /// 所有回收工作都由该方法完成。
        ///     子类应重写(override)该方法。
        /// </summary>
        /// <param name="disposing"></param>
        protected virtual void Dispose(bool disposing)
        {
            // 避免重复调用 Dispose 。
            if (!disposed) return;

            // 适应多线程环境,避免产生线程错误。
            lock (this)
            {
                if (disposing)
                {
                    // ------------------------------------------------
                    // 在此处写释放托管资源的代码
                    // (1) 有 Dispose() 方法的,调用其 Dispose() 方法。
                    // (2) 没有 Dispose() 方法的,将其设为 null。
                    // 例如:
                    //     xxDataTable.Dispose();
                    //     xxDataAdapter.Dispose();
                    //     xxString = null;
                    // ------------------------------------------------
                }

                // ------------------------------------------------
                // 在此处写释放非托管资源
                // 例如:
                //     文件句柄等
                // ------------------------------------------------
                disposed = true;
            }
        }

        /// <summary>
        /// 该方法由程序调用,在调用该方法之后对象将被终结。
        ///     该方法定义在IDisposable接口中。
        /// </summary>
        public void Dispose()
        {
            //因为是由程序调用该方法的,因此参数为true。
            Dispose(true);
            //因为我们不希望垃圾回收器再次终结对象,因此需要从终结列表中去除该对象。
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// 调用 Dispose() 方法,回收资源。
        /// </summary>
        public void Close()
        {
            Dispose();
        }
    }

The application layer calls

    DateTime packetClassStart = DateTime.Now;

    TcpHeartPacketClass tcpHeartPacketClass = neTcpHeartPacketClass(ReceviveBuff);

    DateTime packetClassEnd = DateTime.Now;
    TimeSpan toClassTs = packetClassEnd.Subtra(packetClassStart);
    try
    {
    tcpHeartPacketClass.head[0] = 0x11;
    
    LoggerHelper.Info("类中的包头:" + BitConverteToString(tcpHeartPacketClass.head));
    Console.WriteLine("类中的包头:{0}", BitConverteToString(tcpHeartPacketClass.head));

    LoggerHelper.Info("类中的包类型:" tcpHeartPacketClass.type.ToString());
    Console.WriteLine("类中的包类型:{0}"tcpHeartPacketClass.type.ToString());

    LoggerHelper.Info("类中的包长度:" + BitConverteToString(tcpHeartPacketClass.length));
    Console.WriteLine("类中的包长度:{0}", BitConverteToString(tcpHeartPacketClass.length));

    LoggerHelper.Info("类中的MAC地址:" + BitConverteToString(tcpHeartPacketClass.Mac));
    Console.WriteLine("类中的MAC地址:{0}", BitConverteToString(tcpHeartPacketClass.Mac));

    LoggerHelper.Info("类中的注册包内容:" + BitConverteToString(tcpHeartPacketClass.data));
    Console.WriteLine("类中的注册包内容:{0}"BitConverter.ToString(tcpHeartPacketClass.data));

    LoggerHelper.Info("类中的包尾:" + BitConverteToString(tcpHeartPacketClass.tail));
    Console.WriteLine("类中的包尾:{0}", BitConverteToString(tcpHeartPacketClass.tail));

    Console.WriteLine("字节数组类中分割总共花费{0}ms\n"toClassTs.TotalMilliseconds);
    }
    finally
    {
        IDisposable disposable = tcpHeartPacketClass as IDisposable;
        if (disposable != null)
            disposable.Dispose();
    }

6.Dispose () method in force test

After ty ... finally block executing the Dispose () method, go to a class of property assignment, we look at whether the error, if error assigned to the null object is to prove successful release.

    finally
    {
        IDisposable disposable = tcpHeartPacketClass        IDisposable;
        if (disposable != null)
            disposable.Dispose();
    }
    tcpHeartPacketClass.head[0] = 0x12;

The following error, which translates meaning that there is no corresponding object references an instance, that we have to be freed up.

7. Comparative Test Performance

Can be seen by the figure, the above class is parsed microsecond, and articles layman structure C # - heartbeat packets encapsulated Ethernet configuration example analytic level of several tens of microseconds, the difference almost 5 10 times the performance.

Thus, in this scenario, using a heartbeat packet class to encapsulate the network structure is more reasonable than the package.

8. In summary, the C #, the main effect of the following two structures:

  • The data length is very short, the new 16-byte configuration type, subtype and structures in the body must be a value type, otherwise no meaning, which are designed to accommodate efficient reading on the stack;
  • For compatibility with C from some libraries in C ++;
    avoid the above two points, I think in C # to develop new applications, can be completely replaced with a class structure (only on behalf of personal view).

Disclaimer: This article is a blogger original article, follow the CC 4.0 BY-SA copyright agreement, reproduced, please attach the original source link and this statement.

This link: https://www.cnblogs.com/JerryMouseLi/p/12610332.html

Guess you like

Origin www.cnblogs.com/JerryMouseLi/p/12610332.html