• 用Stream代理bytes[]吧~


      网络读取需要buffer, 就是byte[]数组啦。buffer分配后占用固定内存,size设小了不够用,size设大了造成浪费并且频繁创建对性能有影响;

      需要对buffer进行复用,目前了解有2种方式:

    1. buffer对象池,WCF就用的此方式;

    2. buffer分割,即ArraySegment<byte>;

      无论是上面那种方式,在调用的时候均需要关注buffer,像数组分割还要关心offset等很麻烦。如:

    byte[] buffer = new byte[512];
                Stream stream = new MemoryStream();
                stream.Read(buffer, 0, buffer.Length);
                stream.Write(buffer, 0, buffer.Length);

    换成复用的方式:

                BufferSegment seg = new BufferSegment();
    
                byte[] buffer = seg.Take();
                try
                {
                    Stream stream = new MemoryStream();
                    stream.Read(buffer, 0, buffer.Length);
                    stream.Write(buffer, 0, buffer.Length);
                }
                finally
                {
                    seg.Return(buffer);
                }

    对于调用方来说又依赖了buffer服用对象,即上面的BufferSegment,而且还必须写try-finally,东西没还回去问题就大了,例如SqlConnection的连接池是在.Dispose()时候return连接池的,如果没有.Dispose()就会出现连接不够用的情况。

                BufferSegment seg = new BufferSegment();
    
                using(Buffer item = seg.Take())
                {
                    byte[] buffer = item.Array;
                    Stream stream = new MemoryStream();
                    stream.Read(buffer, 0, buffer.Length);
                    stream.Write(buffer, 0, buffer.Length);
                }

    这种方式把take和return都隐藏掉了,但还是对服用对象BufferSegment产生依赖;

      偶然发现4.0中Stream加了一个CopyTo方法,于是扩展如下~

    public void CopyTo(Stream destination, int bufferSize)

    对外只暴露了buffersize,至于buffer怎么来、怎么去都隐藏掉,减少依赖!

    public static void FixedCopyTo(this Stream instance, Stream destination, int length, Func<bool> perAction = null)
            {
                Contract.Requires(instance != null && instance.CanRead);
                Contract.Requires(destination != null && destination.CanWrite);
    
                B buffer;
                BufferSegment.MemoryBuffer.Take(out buffer);
                try
                {
                    int read;
                    while (length > 0 && (read = instance.Read(buffer.Array, buffer.Offset, Math.Min(buffer.Count, length))) != 0)
                    {
                        destination.Write(buffer.Array, buffer.Offset, read);
                        length -= read;
                        if (perAction != null && !perAction())
                        {
                            break;
                        }
                    }
                }
                finally
                {
                    BufferSegment.MemoryBuffer.Return(ref buffer);
                }
            }

    这些逻辑都被隐藏在内部了!!!调用的时候直接copyto 完事。

    只里有个遗憾就需要源对象和目标对象都需要包装成Stream,如开头就需要把byte[]包装成MemoryStream,但实际上byte[512] 和 new MemoryStream(byte[512])内存查不了几个字节,

                BufferSegment seg = new BufferSegment();
                byte[] buffer = seg.Take();
                try
                {
                    System.Net.Sockets.Socket sock = new System.Net.Sockets.Socket();
                    int recv = sock.Receive(buffer);
                    Stream stream = new MemoryStream();
                    stream.Write(buffer, 0, recv);
                }
                finally
                {
                    seg.Return(buffer);
                }

    就可以换成

    System.Net.Sockets.Socket sock = new System.Net.Sockets.Socket();
                var netStream = new System.Net.Sockets.NetworkStream(sock);
                Stream stream = new MemoryStream();
                netStream.FixedCopyTo(stream);

    仔细观察下.netframework 中的对象,加密、压缩文件等都是Stream,这么多对象都受用,多爽~~~

    现在我压根都不想碰byte[]了。。  见到它就想转成MemoryStream~

  • 相关阅读:
    添加常驻Notification
    Java 数组操作
    一百本英文原著之旅 ( 15 finished )
    SQLServer2005中查询语句的执行顺序
    高效程序员的45个习惯
    博客园经典闪存语录
    for xml path('') 引发的数据不完整
    ajax向前台输出二维数组 并解析
    重视知识的本质
    C语言排序
  • 原文地址:https://www.cnblogs.com/Googler/p/3067014.html
Copyright © 2020-2023  润新知