罗斯林慢启动时间 [英] Roslyn slow startup time

查看:215
本文介绍了罗斯林慢启动时间的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经注意到,启动时间罗斯林解析/编译是一个相当显著的一次性成本。编辑:我使用的是罗斯林CTP MSI(装配在GAC)。难道这正常吗?有没有什么解决方法吗?



运行下面的代码需要几乎相同的时间量与1迭代(〜3秒),与300次迭代(〜3秒)。

  [测试] 
公共无效测试()
{
VAR iters = 300;
的foreach(VAR我在Enumerable.Range(0,iters))
{
//使用解析罗斯林$ B $源文件B SyntaxTree syntaxTree = SyntaxTree.ParseText(@公共类富+ 1 + @{公共无效执行exec(){}});

//添加我们需要编译
变种引用=新的List<的所有引用; MetadataReference>();
references.Add(新MetadataFileReference(typeof运算(int)的.Assembly.Location));

变种compilationOptions =新CompilationOptions(outputKind:OutputKind.DynamicallyLinkedLibrary);

//注意:使用固定装配的名字,这并不重要,只要不希望产生的组件
VAR编译= Compilation.Create(SomeAssemblyName的交叉引用,compilationOptions,新】{} syntaxTree,参考文献);

//生成组装成内存流
变种memStream =新的MemoryStream();

//如果我们从这一行注释掉上下,运行时降至〜0.5秒
EmitResult emitResult = compilation.Emit(memStream);

VAR ASM =的Assembly.Load(memStream.GetBuffer());
变种类型= asm.GetTypes()单(T => t.Name ==富+ I);
}
}


解决方案

我想到一个问题是使用内存流,而不是你应该尝试使用动态模块和ModuleBuilder来代替。总体而言,代码执行速度更快,但仍然有较重的第一负载场景。我是很新,罗斯林自己,所以我不知道为什么这是快,但这里是改变的代码。

  VAR iters = 300; 
的foreach(VAR我在Enumerable.Range(0,iters))
{
//使用解析罗斯林$ B $源文件B SyntaxTree syntaxTree = SyntaxTree.ParseText(@公共类富+ 1 + @{公共无效执行exec(){}});

//添加我们需要编译
变种引用=新名单,LT的所有引用; MetadataReference>();
references.Add(新MetadataFileReference(typeof运算(int)的.Assembly.Location));

变种compilationOptions =新CompilationOptions(outputKind:OutputKind.DynamicallyLinkedLibrary);

//注意:使用固定的程序集的名称,这不要紧,只要我们不期望产生装配
VAR编译= Compilation.Create(SomeAssemblyName跨引用,compilationOptions,新的[] {} syntaxTree,参考文献);

VAR assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(新System.Reflection.AssemblyName(CustomerA),
System.Reflection.Emit.AssemblyBuilderAccess.RunAndCollect);

VAR moduleBuilder = assemblyBuilder.DefineDynamicModule(MyModule的);

System.Diagnostics.Stopwatch手表=新System.Diagnostics.Stopwatch();
watch.Start();

//如果我们从这个线路和下行注释掉,运行时间降到〜0.5秒
VAR emitResult = compilation.Emit(moduleBuilder);

watch.Stop();

System.Diagnostics.Debug.WriteLine(watch.ElapsedMilliseconds);

如果(emitResult.Diagnostics.LongCount()== 0)
{
变种类型= moduleBuilder.GetTypes()单(T =方式> t.Name == 富+ I);

System.Diagnostics.Debug.Write(A型!= NULL); $ B $黑} $ B $黑}



通过使用这种技术的编译只花了96(毫秒)在后续的迭代大约需要3 - 15毫秒。所以,我认为,你可以在第一负载情况下,添加一些开销而言是正确的。



对不起,我无法解释为什么它的速度更快!我只是研究罗斯林自己,会做更多的挖掘今晚稍后,看看我能找到什么样的ModuleBuilder提供过任何的MemoryStream更多的证据。


I've noticed that the startup time for Roslyn parsing/compilation is a fairly significant one-time cost. EDIT: I am using the Roslyn CTP MSI (the assembly is in the GAC). Is this expected? Is there any workaround?

Running the code below takes almost the same amount of time with 1 iteration (~3 seconds) as with 300 iterations (~3 seconds).

[Test]
public void Test()
{
    var iters = 300;
    foreach (var i in Enumerable.Range(0, iters))
    {
        // Parse the source file using Roslyn
        SyntaxTree syntaxTree = SyntaxTree.ParseText(@"public class Foo" + i + @" { public void Exec() { } }");

        // Add all the references we need for the compilation
        var references = new List<MetadataReference>();
        references.Add(new MetadataFileReference(typeof(int).Assembly.Location));

        var compilationOptions = new CompilationOptions(outputKind: OutputKind.DynamicallyLinkedLibrary);

        // Note: using a fixed assembly name, which doesn't matter as long as we don't expect cross references of generated assemblies
        var compilation = Compilation.Create("SomeAssemblyName", compilationOptions, new[] {syntaxTree}, references);

        // Generate the assembly into a memory stream
        var memStream = new MemoryStream();

        // if we comment out from this line and down, the runtime drops to ~.5 seconds
        EmitResult emitResult = compilation.Emit(memStream);

        var asm = Assembly.Load(memStream.GetBuffer());
        var type = asm.GetTypes().Single(t => t.Name == "Foo" + i);
    }
}

解决方案

I think one issue is using a memory stream, instead you should try using a dynamic module and ModuleBuilder instead. Overall the code is executing faster but still has a heavier first load scenario. I'm pretty new to Roslyn myself so I'm not sure why this is faster but here is the changed code.

        var iters = 300;
        foreach (var i in Enumerable.Range(0, iters))
        {
            // Parse the source file using Roslyn
            SyntaxTree syntaxTree = SyntaxTree.ParseText(@"public class Foo" + i + @" { public void Exec() { } }");

            // Add all the references we need for the compilation
            var references = new List<MetadataReference>();
            references.Add(new MetadataFileReference(typeof(int).Assembly.Location));

            var compilationOptions = new CompilationOptions(outputKind: OutputKind.DynamicallyLinkedLibrary);

            // Note: using a fixed assembly name, which doesn't matter as long as we don't expect cross references of generated assemblies
            var compilation = Compilation.Create("SomeAssemblyName", compilationOptions, new[] { syntaxTree }, references);

            var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new System.Reflection.AssemblyName("CustomerA"),
            System.Reflection.Emit.AssemblyBuilderAccess.RunAndCollect);

            var moduleBuilder = assemblyBuilder.DefineDynamicModule("MyModule");

            System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
            watch.Start();

            // if we comment out from this line and down, the runtime drops to ~.5 seconds
            var emitResult = compilation.Emit(moduleBuilder);

            watch.Stop();

            System.Diagnostics.Debug.WriteLine(watch.ElapsedMilliseconds);

            if (emitResult.Diagnostics.LongCount() == 0)
            {
                var type = moduleBuilder.GetTypes().Single(t => t.Name == "Foo" + i);

                System.Diagnostics.Debug.Write(type != null);
            }
        }

By using this technique the compilation took just 96 milliseconds, on subsequent iterations it takes around 3 - 15ms. So I think you could be right in terms of the first load scenario adding some overhead.

Sorry I can't explain why it's faster! I'm just researching Roslyn myself and will do more digging later tonight to see if I can find any more evidence of what the ModuleBuilder provides over the memorystream.

这篇关于罗斯林慢启动时间的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆