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. java 短信发送例子 tdy

    import java.io.IOException; import java.util.logging.Level;import java.util.logging.Logger;import or ...

  2. 转载 Eclipse下的SSH开发例子

    前言 确实好久没有写过了,一直以来把写博文当作自己学习的总结,当作做过的笔记,随时都可以拿出来看看.不过最近习惯了用OneNote和印象笔记,所以就很少在论坛写博文.但是偶尔看到几篇被转载了,也小小的 ...

  3. C++标准程序库读书笔记-第四章通用工具

    1.Pairs(对组) (1)class pair可以将两个值视为一个单元.任何函数需返回两个值,也需要pair. (2)便捷地创建pair对象可以使用make_pair函数 std::make_pa ...

  4. C# 添加服务引用。

    1,服务引用给的实例(需要一个网址连接) http://192.168.17.131:12170/amtiot.gis.WCF/SpatialAnalysis.svc  (类似于这样的一个网址) 在网 ...

  5. HTML5 canvas 在线画笔绘图工具(三)

    组装画板(TDrawBuilder) 在这一小节中我们要把工具条和画板组装起来,让他们可以协同进行工作. 画板通过一个命名为TDrawBuilder来进行组装.在详细讲解TDrawBuilder对象之 ...

  6. Thinkphp excel导入导出

    挺有用处的存一下 1.去PHPexcel 官网下载最新的程序下来 ☞   飞机在这里 我用的是1.78 放在vender 里面 在  function.php 写两个方法 路径当然是这个 ☞Commo ...

  7. 如何看linux是32位还是64位

    查看linux是多少位的几位方法: 查看linux机器是32位还是64位的方法: 方法一: file  /sbin/init 或者 file  /bin/ls 结果如下:/sbin/init: ELF ...

  8. ecshop各个文件夹作用

    Images文件夹: 这个文件夹下有子文件夹,在这些子文件夹下面存放着当前网站商品的原始图片和缩略图.这些子文件夹命名有规律的,它们的文件名是它们目录下商品加入 的年月份.也就是说在同一个月份加入的商 ...

  9. 常用的PHP正则表达式汇总

    PHP中的常用正则表达式集锦: 匹配中文字符的正则表达式: [\u4e00-\u9fa5] 评注:匹配中文还真是个头疼的事,有了这个表达式就好办了 匹配双字节字符(包括汉字在内):[^\x00-\xf ...

  10. python socket 编程之一:编写socket的基本步骤

    一.socket 编写server的步骤: 1.第一步是创建socket对象.调用socket构造函数.如: socket = socket.socket( family, type ) family ...