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();
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代码来证实这种现象,如下:

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("", , () => { }); } 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 + ]; for (int i = ; i <= GC.MaxGeneration; i++) {
gcCounts[i] = GC.CollectionCount(i); } // 3. Stopwatch watch = new Stopwatch(); watch.Start(); long cycleCount = GetCycleCount(); for (int i = ; i < iteration; i++) action(); long cpuCycles = GetCycleCount() - cycleCount; watch.Stop(); // 4. Console.ForegroundColor = currentForeColor; Console.WriteLine("\tTime Elapsed:\t" + watch.ElapsedMilliseconds.ToString("N0") + "ms"); Console.WriteLine("\tCPU Cycles:\t" + cpuCycles.ToString("N0")); // 5. for (int i = ; i <= GC.MaxGeneration; i++) {
int count = GC.CollectionCount(i) - gcCounts[i];
Console.WriteLine("\tGen " + i + ": \t\t" + 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(); } }

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

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 = * *; 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编译器知道类型的构造器已经被调用了,所以第二次执行时不会显示对构造函数进行调用。

 

beforefieldinit释义(3)的更多相关文章

  1. beforefieldinit释义(2)

    首先来看一段代码: using System; namespace BeforeFieldInit { internal class Foo { Foo(){ Console.WriteLine(&q ...

  2. beforefieldinit释义

    首先让我们认识什么是,当字段被标记为beforefieldinit类型时,该字段初始化可以发生在任何时候任何字段被引用之前.这句话听起了有点别扭,接下来让我们通过具体的例子介绍. /// <su ...

  3. 常见linux命令释义(第八天)—— Bash Shell 的操作环境

    换了新公司,公司的领导很不错.自己感受比较多的地方是,自己的工作效率明显比以前高了.以前会对频繁变动的需求十分不耐烦,现在接到需求后会仔细的思考,进行整体构建.即使以后需求有变动,也能够比较轻易的在原 ...

  4. 常见linux命令释义(第三天)

    今天晚上看鸟哥的私房菜,边学边写笔记. 在linux中压缩大多是.tar, .tar.gz , .tgz, /gz, .bz2等. .gz 是通过gzip压缩的文件. .bz2 是通过bzip2压缩的 ...

  5. 常见linux命令释义(第一天)

    快到中午吃饭了,然后忽然想起来samba里面没有添加用户.于是乎,就玩弄起了samba. Samba三下五除二就安装好了,想想window里面不断的点击下一步,还要小心提防各种隐藏再角落里的绑定软件. ...

  6. Tomcat的目录结构、处理流程、主配置文件(server.xml)释义

    参考资料: http://www.cnblogs.com/xdp-gacl/p/3744053.html http://grass51.blog.51cto.com/4356355/1123400 1 ...

  7. 使用Perl5获取有道词典释义

    Get Word Definition from dict.youda.com via Perl Script 获取基本释义 Get Basic Definition http://dict.youd ...

  8. Web前端名词释义及原理

    引言:看题目的时候,不要觉得这是一个很深奥的问题,Web前端这些东西很多就是叫的名字牛逼,其实原理很TM简单,也就那么回事. 一.javascript名词释义 1.啥是事件队列? 就是 弄一个数组,里 ...

  9. linux内核的冒险md来源释义# 14raid5非条块读

    linux内核的冒险md来源释义# 14raid5非条块读 转载请注明出处:http://blog.csdn.net/liumangxiong 假设是非条块内读.那么就至少涉及到两个条块的读,这就须要 ...

随机推荐

  1. [KMP求最小循环节][HDU1358][Period]

    题意 求所有循环次数大于1的前缀 的最大循环次数和前缀位置 解法 直接用KMP求最小循环节 当满足i%(i-next[i])&&next[i]!=0 前缀循环次数大于1 最小循环节是i ...

  2. php错误日志级别

    ; E_ALL             所有错误和警告(除E_STRICT外) ; E_ERROR           致命的错误.脚本的执行被暂停. ; E_RECOVERABLE_ERROR   ...

  3. C#实现WinForm传值实例解析

    C#实现WinForm传值的问题经常会做为公司面试的题目,那么作为学习C#以及WinForm传值,我们需要掌握哪些方法和思路呢?下面我们就向你介绍详细的思路和实现的具体步骤,希望对你有所帮助. C#实 ...

  4. Sql语句之查询所有学生所有科目分数及总分

    昨天练Sql语句,数据库建了四个表分别是,学生表,课程表,成绩表以及教师表(教师表不在讨论范围),突然想到以前高中时代老师手上的那张成绩表,然后我就寻思着能不能用Sql语句把表打印出来,以下是我的思考 ...

  5. dojo.io.script

    dojo.io.script 定义: 跨域访问数据,可以动态的将script标签插入到网页当中. 局限: 1.只支持get方式访问: 2.只支持异步调用. 使用: 1.dojo.io.script.g ...

  6. Oracle闪回详解

      1.问题定义 闪回是dba做的工作.现在也可授权给某个用户. 闪回的定义:就是将用户错误的操作回恢到以前的状态.即使你的事务提交的commit. 如果你删除了一个表.Drop table(DDL) ...

  7. HDU 1070 - Milk

    给每种牛奶价格和量 要求买最便宜的牛奶 #include <iostream> using namespace std; int t,n; ][]; ],v[]; int main() { ...

  8. oracle中job定时调用存储过程的实例

    使用job模拟定时从元数据表中抽取指定数据进入目标表的过程. 一.创建元数据表 --create table test_origianl create table test_original_data ...

  9. pat_1

    2-0 2-1 #include <stdio.h> int main() { int inch,foot,cm; scanf("%d",&cm); foot= ...

  10. win8上安装 Pillow

    1.确保正确安装pip(2.7.9默认安装) 2. pip install wheel 3.下载 pillow-*.whl 根据自己的电脑和python版本 地址 4.安装 pip install x ...