首页 > 解决方案 > 如何缓存程序集以供以后编译?[罗斯林]

问题描述

在我的项目中,我将为每次编译(大约 30 个 dll)使用相同的参考程序集编译大量程序集。似乎在第一次编译参考程序集被缓存后,从第二次编译(1360ms -> 40ms)开始实现了巨大的速度提升。我想在编译新程序集之前缓存所有引用程序集。

程序集在方法期间被缓存CSharpCompilation.Create(name, syntaxTrees, references)。这个方法需要syntaxTree编译,但我只想缓存引用。我需要调用什么来缓存引用?

主要编译代码:

List<MetadataReference> references = new List<MetadataReference>();
foreach (var reference in assemblies)
{
   try
   {
      references.Add(MetadataReference.CreateFromFile(reference));
   }
   catch (Exception e)
   {
      error += e + "\n";
      exitCode |= (int)ExitCode.ReferenceError;
   }
}

CSharpCompilation compilation = null;
compilation = CSharpCompilation.Create(
   assemblyName,
   syntaxTrees: syntaxTree,
   references: references,
   options: new CSharpCompilationOptions(
      OutputKind.DynamicallyLinkedLibrary,
      optimizationLevel: OptimizationLevel.Release,
      allowUnsafe: true));

标签: c#.netroslyn

解决方案


请注意,“首次运行”的成本可能不是消耗的程序集,而只是运行时必须 JIT Roslyn 本身;后来的编译也利用了这一事实。

也就是说,我们在创建的编译之间重用加载的元数据信息的幕后已经有缓存。只要我们认识到这些程序集正在被重用,它们就会自动启动。确保使用缓存的最佳方法是重用您从 CreateFromFile 返回的相同 MetadataReference 对象,以简化被触发的缓存。但是您实际上并不需要进行任何显式缓存——我们已经为您做到了!

请注意,您还可以从现有编译创建编译,但替换语法树;因此您可以仅使用引用进行单个编译,然后将其调用 .WithSyntaxTree() 以使用这些树生成新的编译 - 您可以继续返回第一个编译并用新树“分叉”它。这也可能会更快一些,但您必须相应地对其进行基准测试。


推荐阅读