在一个项目中,需要轻量级用到脚本语言,来提高应用服务的灵活性。因为知道Roslyn可以动态编辑C#,本着情怀,就自然用Roslyn来处理这块业务了。开在windows上执行,一次调用风平浪静,因为这个功能使用频次不高,性能也没有太在意,上线后一切安好。事情发生在n天后,随着数据的增多,批量的数据上来了,批量使用这个功能时,把pod(我们的环境是kubernetes)使用爆炸了,只要用这个功能的批量,pod就会重启,从而造成了生产事故。
完后,我对这个功能作了一次测试,附上内存使用情况。
下图是windows上的测试结果,内存还有机会释放
下图是docker上的结果,内存只增不减
看图,觉得在windows上效果还好一些,但对于生产,其实都是要命的,如图,即使在windows上,内存的起伏也是巨大的。
Roslyn的代码如下:
using Microsoft.CodeAnalysis; using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Runtime; using System.Text; using System.Globalization; using Microsoft.CodeAnalysis.CSharp; using Newtonsoft.Json; using Smart.Text.Japanese; namespace NLuaAndRoslynCompare5 { public class RoslynClass { public static object Transform(string csharp,params object[] pares) { var sourceCodeText = $@" using System; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; using System.Linq; using Smart.Text.Japanese; using System.Globalization; namespace RoslynDynamicGenerate {{ public class DynamicGenerateClass {{ public object Generate(object par) {{ {csharp} }} }} }} "; var syntaxTree = CSharpSyntaxTree.ParseText(sourceCodeText, new CSharpParseOptions(LanguageVersion.Latest)); // 获取代码分析得到的语法树 var assemblyName = $"RoslynDynamicGenerate"; // 创建编译任务 var metadata = GetMetadataReference(typeof(System.Text.RegularExpressions.Regex),typeof(StringExpand), typeof(KanaConverter), typeof(List<>), typeof(IDictionary), typeof(JapaneseCalendar),typeof(CultureInfo),typeof(DateTime), typeof(JsonConvert), typeof(object), typeof(AssemblyTargetedPatchBandAttribute)); var compilation = CSharpCompilation.Create(assemblyName) //指定程序集名称 .WithOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary))//输出为 dll 程序集 .AddReferences(metadata) //添加程序集引用 .AddSyntaxTrees(syntaxTree) // 添加上面代码分析得到的语法树 ; using (var memory = new MemoryStream()) { var compilationResult = compilation.Emit(memory); if (compilationResult.Success) { try { var assembly = Assembly.Load(memory.ToArray()); var type = assembly.GetType("RoslynDynamicGenerate.DynamicGenerateClass"); var obj = Activator.CreateInstance(type); var methodInfo = type.GetMethod("Generate"); return methodInfo.Invoke(obj, pares)?.ToString(); } finally { memory.Close(); } } else { foreach (var diagnositic in compilationResult.Diagnostics) { Console.WriteLine(diagnositic); } throw new ApplicationException($"下面C#语句有语法错误{sourceCodeText}"); } } } /// <summary> /// 从类型获取原数据引用 /// </summary> /// <param name="types">类型集合</param> /// <returns></returns> static List<MetadataReference> GetMetadataReference(params Type[] types) { var list = new List<MetadataReference>(); foreach (var type in types) { var metadateRef = MetadataReference.CreateFromFile(type.Assembly.Location); list.Add(metadateRef); foreach (var assembly in type.Assembly.GetReferencedAssemblies()) { list.Add(MetadataReference.CreateFromFile(Assembly.Load(assembly).Location)); } } return list; } } }
调用方法如下:
List<string> Roslyn() { var list = new List<string>(); var csharp = @"return DateTime.Now.ToString(""yyyy-MM-dd HH:mm:ss.ffffff""); "; for (int i = 0; i < 1000; i++) { list.Add(RoslynClass.Transform(csharp, 1).ToString()); } return list; }
现在是换方式的时候了!!!
想要更快更方便的了解相关知识,可以关注微信公众号