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
{
Console.WriteLine("
Console.WriteLine("int: " + MyClass<int>.Time);
Thread.Sleep(3000);
Console.WriteLine("string: " + MyClass<string>.Time);
Console.ReadLine();
}
}
结果如下:
GetNow execute!
GetNow 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("", 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("\tTime Elapsed:\t" + watch.ElapsedMilliseconds.ToString("N0") + "ms");
Console.WriteLine("\tCPU Cycles:\t" + cpuCycles.ToString("N0"));
// 5.
for (int i = 0; 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
{
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编译器知道类型的构造器已经被调用了,所以第二次执行时不会显示对构造函数进行调用。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器