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();
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)的更多相关文章
- beforefieldinit释义(2)
首先来看一段代码: using System; namespace BeforeFieldInit { internal class Foo { Foo(){ Console.WriteLine(&q ...
- beforefieldinit释义
首先让我们认识什么是,当字段被标记为beforefieldinit类型时,该字段初始化可以发生在任何时候任何字段被引用之前.这句话听起了有点别扭,接下来让我们通过具体的例子介绍. /// <su ...
- 常见linux命令释义(第八天)—— Bash Shell 的操作环境
换了新公司,公司的领导很不错.自己感受比较多的地方是,自己的工作效率明显比以前高了.以前会对频繁变动的需求十分不耐烦,现在接到需求后会仔细的思考,进行整体构建.即使以后需求有变动,也能够比较轻易的在原 ...
- 常见linux命令释义(第三天)
今天晚上看鸟哥的私房菜,边学边写笔记. 在linux中压缩大多是.tar, .tar.gz , .tgz, /gz, .bz2等. .gz 是通过gzip压缩的文件. .bz2 是通过bzip2压缩的 ...
- 常见linux命令释义(第一天)
快到中午吃饭了,然后忽然想起来samba里面没有添加用户.于是乎,就玩弄起了samba. Samba三下五除二就安装好了,想想window里面不断的点击下一步,还要小心提防各种隐藏再角落里的绑定软件. ...
- Tomcat的目录结构、处理流程、主配置文件(server.xml)释义
参考资料: http://www.cnblogs.com/xdp-gacl/p/3744053.html http://grass51.blog.51cto.com/4356355/1123400 1 ...
- 使用Perl5获取有道词典释义
Get Word Definition from dict.youda.com via Perl Script 获取基本释义 Get Basic Definition http://dict.youd ...
- Web前端名词释义及原理
引言:看题目的时候,不要觉得这是一个很深奥的问题,Web前端这些东西很多就是叫的名字牛逼,其实原理很TM简单,也就那么回事. 一.javascript名词释义 1.啥是事件队列? 就是 弄一个数组,里 ...
- linux内核的冒险md来源释义# 14raid5非条块读
linux内核的冒险md来源释义# 14raid5非条块读 转载请注明出处:http://blog.csdn.net/liumangxiong 假设是非条块内读.那么就至少涉及到两个条块的读,这就须要 ...
随机推荐
- Android多项目依赖在Eclipse中无法关联源代码的问题解决 Ctril 点不进去的解决方法
1. 使用快捷键:Ctrl+shift+R,在弹出框中输入.classpath 找到被作为library引入的那个.classpath文件. 2.将kind="src" path ...
- SQL查询语句47题
select * from student select * from score --select * from grade select * from course select * from t ...
- union以及一些扩展
select name,age from Students where Age<3unionselect name ,age from Students where Age >4--两个结 ...
- data source 和initial catalog
initial catalog与database的区别是什么Initial Catalog: DataBase: 两者没有任何区别只是名称不一样,就好像是人类的真实姓名与曾用名一样..都可以叫你. * ...
- c# 打开、保存文件对话框 和 文件夹选择对话框
1. OpenFileDialog openImageDialog = new OpenFileDialog(); openImageDialog.Filter = "Image Files ...
- 正确合理的建立MYSQL数据库索引
写在前面:索引对查询的速度有着至关重要的影响,理解索引也是进行数据库调优的起点.考虑如下情况,假设数据库中一个表有10^6条记录,DBMS的页面大小为4K,并存储100条记录.如果没有索引,查询将对整 ...
- 解决在IE浏览器下 boder边框出现断裂或虚线的问题
ie6.0下面经常会出现border边框断断续续的问题,等深一步了解了div之后自然会经常碰到这种问题了,不过初学div+css 的一般不会用遇到这个问题,因为初学者不会偷懒,等我们觉得用的很熟了,各 ...
- hibernate联合主键注解配置
在网上看到好多方法,结果拿来用还是出现了一些问题.现在整理一下 1.主键类 import javax.persistence.Column; public class UserRoleUionPK i ...
- android studio error configuration with name default not found
Android Studio报错: android studio error configuration with name default not found 在进行sync的时候,提示Error: ...
- LayoutInflater的获取方式
1.LayoutInflater是什么? 通俗而讲,就是将xml中定义的布局找出来. 2.获取LayoutInflater的三种方式 1. LayoutInflater inflater = ge ...