国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > C# > 正文

如何獲取C#中方法的執行時間以及其代碼注入詳解

2019-10-29 19:57:59
字體:
來源:轉載
供稿:網友

前言

在優化C#代碼或對比某些API的效率時,通常需要測試某個方法的運行時間,可以通過DateTime來統計指定方法的執行時間,也可以使用命名空間System.Diagnostics中封裝了高精度計時器QueryPerformanceCounter方法的Stopwatch類來統計指定方法的執行時間:

1.使用DateTime方法:

DateTime dateTime = DateTime.Now;MyFunc();Console.WriteLine((DateTime.Now - dateTime).TotalMilliseconds);

2.使用Stopwatch方式:

Stopwatch stopwatch = new Stopwatch();stopwatch.Start();MyFunc();stopwatch.Stop();Console.WriteLine(stopwatch.ElapsedMilliseconds); //本次MyFunc()方法的運行毫秒數//重置計時器stopwatch.Restart(); //此處可以使用stopwatch.Reset(); stopwatch.Start();組合代替MyFunc();stopwatch.Stop();Console.WriteLine(stopwatch.ElapsedMilliseconds); //本次MyFunc()方法的運行毫秒數

以上兩種辦法都可以達到獲取方法執行時間的目的,但是在需要對整個項目中的方法都進行監測用時時,除了使用性能分析工具,我們還可以通過代碼注入的方式給程序集中每一個方法加入計時器;

通過命名空間System.Reflection.Emit中的類可以動態的創建程序集、類型和成員,通常類庫Mono.Cecil可以動態讀取并修改已經生成的IL文件,這種在不修改源代碼的情況下給程序集動態添加功能的技術稱為面向切面編程(AOP);

這里給出了一個注入使用Stopwatch來檢測方法執行時間的代碼,這里的Mono.Cecil類庫可以通過nuget進行安裝:

using System;using System.IO;using System.Linq;using System.Diagnostics;using Mono.Cecil;using Mono.Cecil.Cil;using Mono.Collections.Generic;
static void Main(string[] args) { for (int i = 0; i < args.Length; i++) { FileStream fileStream = new FileStream(args[i], FileMode.Open); if (fileStream != null) { AssemblyDefinition aD = AssemblyDefinition.ReadAssembly(fileStream); ModuleDefinition mD = aD.MainModule; Collection<TypeDefinition> typeDefinition = mD.Types; foreach (TypeDefinition type in typeDefinition) {  if (type.IsClass)  {  foreach (MethodDefinition method in type.Methods)  {  if (method.IsPublic && !method.IsConstructor)  {  ILProcessor il = method.Body.GetILProcessor();  TypeReference stT = mD.ImportReference(typeof(Stopwatch));  VariableDefinition stV = new VariableDefinition(stT);  method.Body.Variables.Add(stV);  Instruction first = method.Body.Instructions.First();  il.InsertBefore(first, il.Create(OpCodes.Newobj,                       mD.ImportReference(typeof(Stopwatch).GetConstructor(new Type[] { }))));  il.InsertBefore(first, il.Create(OpCodes.Stloc_S, stV));  il.InsertBefore(first, il.Create(OpCodes.Ldloc_S, stV));  il.InsertBefore(first, il.Create(OpCodes.Callvirt,                      mD.ImportReference(typeof(Stopwatch).GetMethod("Start"))));  Instruction @return = method.Body.Instructions.Last();  il.InsertBefore(@return, il.Create(OpCodes.Ldloc_S, stV));  il.InsertBefore(@return, il.Create(OpCodes.Callvirt,                       mD.ImportReference(typeof(Stopwatch).GetMethod("Stop"))));  il.InsertBefore(@return, il.Create(OpCodes.Ldstr, $"{method.FullName} run time: "));  il.InsertBefore(@return, il.Create(OpCodes.Ldloc_S, stV));  il.InsertBefore(@return, il.Create(OpCodes.Callvirt,                       mD.ImportReference(typeof(Stopwatch).GetMethod("get_ElapsedMilliseconds"))));  il.InsertBefore(@return, il.Create(OpCodes.Box, mD.ImportReference(typeof(long))));  il.InsertBefore(@return, il.Create(OpCodes.Call,                       mD.ImportReference(typeof(string).GetMethod("Concat", new Type[] { typeof(object), typeof(object) }))));  il.InsertBefore(@return, il.Create(OpCodes.Call,                       mD.ImportReference(typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }))));  }  }  } } FileInfo fileInfo = new FileInfo(args[i]); string fileName = fileInfo.Name; int pointIndex = fileName.LastIndexOf('.'); string frontName = fileName.Substring(0, pointIndex); string backName = fileName.Substring(pointIndex, fileName.Length - pointIndex); string writeFilePath = Path.Combine(fileInfo.Directory.FullName, frontName + "_inject" + backName); aD.Write(writeFilePath); Console.WriteLine($"Success! Output path: {writeFilePath}"); fileStream.Dispose(); } } Console.Read(); }

完整的項目傳到了Github上=>InjectionStopwatchCode,下載項目后,通過dotnet build命令即可編譯出可執行程序,將目標程序集文件拖入到該應用程序即可在程序集目錄導出注入代碼后的程序集文件,經過測試,包括方法擁有返回值和方法的參數列表中包含out和ref參數等情況都不會對運行結果產生影響;

示例:

using System;public class MyClass{ public void MyFunc() { int num = 1; for (int i = 0; i < int.MaxValue; i++) { num++; } }}public class Program{ public static void Main(string[] args) { MyClass myObj = new MyClass(); myObj.MyFunc(); Console.Read(); }}

原始IL代碼:

C#,執行時間,代碼注入

代碼注入后IL代碼:

C#,執行時間,代碼注入

代碼注入后運行結果:

 C#,執行時間,代碼注入

 總結:

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對VEVB武林網的支持。


注:相關教程知識閱讀請移步到c#教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 且末县| 大港区| 金堂县| 安达市| 宜兴市| 凤冈县| 临安市| 周口市| 巫溪县| 荣昌县| 罗江县| 万源市| 临高县| 横峰县| 武义县| 芮城县| 军事| 泽库县| 香格里拉县| 恩平市| 蛟河市| 理塘县| 商水县| 镇雄县| 收藏| 永善县| 沙坪坝区| 腾冲县| 泾阳县| 革吉县| 黄平县| 福泉市| 凤凰县| 武邑县| 偏关县| 长寿区| 静海县| 三门峡市| 黄浦区| 临泽县| 鹿邑县|