zoukankan      html  css  js  c++  java
  • 使用Encoding进行字符编码时注意的细节

        一般在对字符进行编码的时候都会使用Encoding.GetBytes方法来进行,但当你在使用该方法的时候有没了解这个方法呢?其实Encoding.GetBytes提供了很多方法不过一般都会直接使用Encoding.GetBytes(string).那使用这个方法会有什么问题呢?通过反编译工具看一下这个方法的实现代码.

    public virtual byte[] GetBytes(string s)
    {
    	if (s == null)
    	{
    		throw new ArgumentNullException("s", Environment.GetResourceString("ArgumentNull_String"));
    	}
    	char[] array = s.ToCharArray();
    	return this.GetBytes(array, 0, array.Length);
    }

        从反编译的代码来看是从s.ToCharArray()返回一个char[]数据,打开这个方法再细看一下

    public unsafe char[] ToCharArray()
    {
    	int length = this.Length;
    	char[] array = new char[length];
    	if (length > 0)
    	{
    		fixed (char* ptr = &this.m_firstChar)
    		{
    			fixed (char* ptr2 = array)
    			{
    				string.wstrcpyPtrAligned(ptr2, ptr, length);
    			}
    		}
    	}
    	return array;
    }

        从代码上来看是构建一个新的char[]把内容复制,到这里可以看到通过这个方法编码必然会创建一个新的char[],返回到GetBytes方法看下return this.GetBytes(array, 0, array.Length);实现又是怎样的

    public virtual byte[] GetBytes(char[] chars, int index, int count)
    {
    	byte[] array = new byte[this.GetByteCount(chars, index, count)];
    	this.GetBytes(chars, index, count, array, 0);
    	return array;
    }

        原理和String.ToArray一样返回一个新的byte[],从以上分析来看就是说一个string的默认方法编码会构建新的char[]和byte[].这意味着会有内存产生和回收,.net下内存分配应该说是很高效的,但内存自动回收GC的是一件比较麻烦的事情,其实通过工具分析GC在程序的整个生命周期占用分额其实也不低的.特别是在大量内存需要回收的时候更加要命.

        其实Encoding和String都提供相关方法可以避免这些对象的开销

        string:

    public unsafe void CopyTo(int sourceIndex, char[] destination, int destinationIndex, int count)

        encoding:

    public abstract int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex);

       都提供一些带char[]和byte[]传入的方法,通过这些方法复用char[]和byte[];这样做除了可以减少内存的开销回收还能提供程序的效率.为了使用这些方法简单地构建一个可复用对象

    public class EncodingData
            {
                public byte[] Bytes = new byte[1024*8];
                public char[] Chars = new char[1024 * 8];
            }

       构建一个对应的应用池

    static Stack<EncodingData> Pool = new Stack<EncodingData>();
            static EncodingData Pop()
            {
                lock (Pool)
                {
                    return Pool.Pop();
                }
            }
            static void Push(EncodingData data)
            {
                lock (Pool)
                {
                    Pool.Push(data);
                }
            }

        实现起来比较简单,下面看一下实际应用的效果,写一个简单的测用例

    private static void test(string text)
            {
                Console.WriteLine("string length:" + text.Length);
                System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
                sw.Reset();
                sw.Start();
                for (int i = 0; i < 10000; i++)
                {
                    Encoding.UTF8.GetBytes(text);
                }
                sw.Stop();
                Console.WriteLine(sw.Elapsed.TotalMilliseconds);
                sw.Reset();
                sw.Start();
                for (int i = 0; i < 10000; i++)
                {
                    EncodingData ed = Pop();
                    text.CopyTo(0, ed.Chars, 0, text.Length);
                    Encoding.UTF8.GetBytes(ed.Chars, 0, text.Length, ed.Bytes, 0);
                    Push(ed);
                }
                sw.Stop();
                Console.WriteLine(sw.Elapsed.TotalMilliseconds);
            }

        测试结果

        虽然测试过程偏向于默认的GetBytes方法,因为GC所占用的时间不能在这里统计进去,但是出来的效果明显是可复用缓冲的方式比默认方法要高效很多.

    访问Beetlex的Github
  • 相关阅读:
    C++------------------>深浅拷贝的问题
    超越 EfficientNet与MobileNetV3,NeurIPS 2020 微软NAS方向最新研究
    数学之美
    mobilenetV2--->特点
    安装R语言扩展包vegan
    每日积累新知识
    安装生物信息学软件-R
    安装生物信息学软件-MetaPhlAn2
    概率统计&假设检验-1
    Population-based metagenomics analysis reveals markers for gut microbiome composition and diversity
  • 原文地址:https://www.cnblogs.com/smark/p/2471312.html
Copyright © 2011-2022 走看看