zoukankan      html  css  js  c++  java
  • beforefieldinit释义(3)

    1.看下面的例子:

    public static class MyClass<T>
    
    {
        public static readonly DateTime Time = GetNow();
        private static DateTime GetNow()
        {
            Console.WriteLine("GetNow execute!");
            return DateTime.Now;
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
    
            Console.WriteLine("Main execute!");
            Console.WriteLine("int: " + MyClass<int>.Time);
            Thread.Sleep(3000);
            Console.WriteLine("string: " + MyClass<string>.Time);
            Console.ReadLine();
        }
    }

    结果如下:

    GetNow execute!

    GetNow execute!

    Main execute!

    int: 2009/9/8 15:34:31

    string: 2009/9/8 15:34:31

    看上面的结果在Main函数执行之前GetNow就执行了,就取到了DateTime.Now,所以输出的时间是一样的。

    2.我们在上面的MyClass中加一个静态的构造函数我们在来看结果:

    public static class MyClass<T>
    
    {
        public static readonly DateTime Time = GetNow();
        private static DateTime GetNow()
        {
    
            Console.WriteLine("GetNow execute!");
            return DateTime.Now;
        }
        static MyClass() { }
    }

    结果如下:

    Main execute!

    GetNow execute!

    int: 2009/9/8 15:40:12

    GetNow execute!

    string: 2009/9/8 15:40:15

    我们可以发现每次的时间不同了。出现这种现象是由于当类没有静态构造函数的时候。在il中该类会被标记为BeforeFieldInit,这个是由编译器自动完成的。没有静态构造函数的时候初始化在刚进入方法的时候就发生了,而有静态函数的时候而且我们不需要做任何动作,只要有就可以,这个时候静态初始化在使用前才发生.我们可以通过看IL代码来证实这种现象,如下:

    clip_image002

    3.使用BeforeFieldInit会提高性能,下面我们就测试下,在测试我们需要计算代码执行时间,我们就是用老赵的组件,我稍稍做了一点修改,因为老赵用的win32 API是vista下的,为了以后查询方便,也贴下代码:

    using System;
    
    using System.Collections.Generic;
    
    using System.Linq;
    
    using System.Text;
    
    using System.Diagnostics;
    
    using System.Threading;
    
    using System.Runtime.InteropServices; 
    
    namespace CSharpDemo
    
    {
        public static class CodeTimer
    
        {
    
            public static void Initialize()
    
            {
    
                Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
    
                Thread.CurrentThread.Priority = ThreadPriority.Highest;
    
                Time("", 1, () => { });
    
            } 
    
            public static void Time(string name, int iteration, Action action)
    
            {
    
                if (String.IsNullOrEmpty(name)) return;
    
                // 1.
    
                ConsoleColor currentForeColor = Console.ForegroundColor;
    
                Console.ForegroundColor = ConsoleColor.Yellow;
    
                Console.WriteLine(name); 
    
                // 2.
    
                GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
    
                int[] gcCounts = new int[GC.MaxGeneration + 1];
    
                for (int i = 0; i <= GC.MaxGeneration; i++)
    
                {
                    gcCounts[i] = GC.CollectionCount(i);
    
                } 
    
                // 3.
    
                Stopwatch watch = new Stopwatch();
    
                watch.Start();
    
                long cycleCount = GetCycleCount();
    
                for (int i = 0; i < iteration; i++) action();
    
                long cpuCycles = GetCycleCount() - cycleCount;
    
                watch.Stop(); 
    
                // 4.
    
                Console.ForegroundColor = currentForeColor;
    
                Console.WriteLine("	Time Elapsed:	" + watch.ElapsedMilliseconds.ToString("N0") + "ms");
    
                Console.WriteLine("	CPU Cycles:	" + cpuCycles.ToString("N0")); 
    
                // 5.
    
                for (int i = 0; i <= GC.MaxGeneration; i++)
    
                {
                    int count = GC.CollectionCount(i) - gcCounts[i];
                    Console.WriteLine("	Gen " + i + ": 		" + count);
                } 
    
                Console.WriteLine();
    
            } 
    
            private static long GetCycleCount()
    
            {
                long l;
    
                long kernelTime, userTimer;
    
                GetThreadTimes(GetCurrentThread(), out l, out l, out kernelTime, out userTimer);
    
                return kernelTime + userTimer; 
    
            } 
    
            [DllImport("kernel32.dll", SetLastError = true)]
    
            static extern bool GetThreadTimes(IntPtr hThread, out long lpCreationTime,
    
               out long lpExitTime, out long lpKernelTime, out long lpUserTime); 
    
            [DllImport("kernel32.dll")]
    
            static extern IntPtr GetCurrentThread(); 
    
        }
    
    }
    View Code

    下面我们开始测试,我们准备两个类:

    public class MarkBeforeFieldInit
    
    {
    
        public static string test;
    
    } 
    
    public class NoBeforeFieldInit
    
    {
        public static string test;
        static NoBeforeFieldInit()
    
        {       
    
        }
    }

    测试代码如下:

    class Program
    
    {
    
        static void Main(string[] args)
    
        {
            CodeTimer.Initialize();
            int iteration = 1000 * 1000*1000; 
    
            CodeTimer.Time("MarkBeforeFieldInit", iteration, () => { MarkBeforeFieldInit.test = "test"; });
    
            CodeTimer.Time("NoBeforeFieldInit", iteration, () => { NoBeforeFieldInit.test= "test"; }); 
    
            CodeTimer.Time("MarkBeforeFieldInit2", iteration, () => { MarkBeforeFieldInit.test = "test"; });
    
            CodeTimer.Time("NoBeforeFieldInit2", iteration, () => { NoBeforeFieldInit.test = "test"; });     
    
        }
    }

    结果如下:

     

    可以看出BeforeFieldInit方式的执行速度确实快,但为什么第二次执行的速度差不多呢?因为经过第一次执行后JIT编译器知道类型的构造器已经被调用了,所以第二次执行时不会显示对构造函数进行调用。

     
  • 相关阅读:
    2020-05-12 Linux基本操作
    SpringBoot项目设置能访问静态资源,resource/static目录下文件
    2020-04-25 Hadoop框架学习
    2020-05-24 vue简单语法
    2020-04-25 elasticsearch
    2020-04-25 kafka
    2020-04-11 函数式数据处理(Java8)
    2020-03-29 分布式事务解决方案(RocketMQ)
    配置文件示例
    Spring-data-redis实现消息队列的demo(附源码)
  • 原文地址:https://www.cnblogs.com/HappyEDay/p/5417182.html
Copyright © 2011-2022 走看看