跳到主要内容

2.1 智能编译模式 - 实现程序集

为何使用实现程序集

实现程序集包括逻辑的具体实现和私有字段,预热内存涨幅较少,但实现程序集具有敏感的依赖关系,需要小心使用。

前提条件

  1. 引入 DotNetCore.Natasha.CSharp.Compiler.Domain Core 版本的编译域包。
  2. 使用预热方法为智能编译做准备。
  3. 智能编译。

预热案例

链式预热

从 V9 版本起,Natasha 支持链式预热:

NatashaManagement
//获取链式构造器
.GetInitializer()
//使用引用程序集中的命名空间
.WithRefUsing()
//使用引用程序集中的元数据
.WithRefReference()
//使用内存中的命名空间
.WithMemoryUsing()
//使用内存中的元数据
.WithMemoryReference()
//使用文件来持久化缓存 命名空间
.WithFileUsingCache()
//过滤哪些元数据是不能用的,被排除的
.WithExcludeReferences((asm, asmStr) => { return false; })
//注册域构造器
.Preheating<NatashaDomainCreator>();

如果不指定相关 API ,预热将跳过此行为,例如只写 WithXXXReference 不写 using 相关的 API, 那么 Natasha 预热时将只对元数据进行操作,不会缓存 using code. 这样做的好处是实现了高度定制化,按需预热。

普通预热

  1. 泛型预热方法将自动创建 编译域创建者 单例。
  2. 传入 true 参数以达到禁用运行时程序集的作用,Natasha 将会选择内存程序集预热。
  3. 第一个参数指是否从内存程序集中提取 Using Code, 设置为 true 将从实现程序集中提取 Using。
  4. 第二个参数指是否从内存程序集中提取 元数据,设置为 true 将从实现程序集中提取 元数据。
//注册编译域并预热方法
NatashaManagement.Preheating<NatashaDomainCreator>(true, true);
//或者 V9 版本
NatashaManagement
//获取链式构造器
.GetInitializer()
//使用引用程序集中的命名空间
.WithMemoryUsing()
//使用内存中的元数据
.WithMemoryReference()
//注册域构造器
.Preheating<NatashaDomainCreator>();

Using缓存预热

指定第三个参数,第一次生成将 Using Code 写入缓存文件 Natasha.Namespace.cache 中,后续重启会自动从文件中加载。

//注册编译域并预热方法
NatashaManagement.Preheating<NatashaDomainCreator>(true, truetrue);
//或者 V9 版本
NatashaManagement
//获取链式构造器
.GetInitializer()
//使用引用程序集中的命名空间
.WithMemoryUsing()
//使用内存中的元数据
.WithMemoryReference()
//使用文件来持久化缓存 命名空间
.WithFileUsingCache()
//注册域构造器
.Preheating<NatashaDomainCreator>();

分开预热

//注册编译域
NatashaManagement.RegistDomainCreator<NatashaDomainCreator>();
//预热方法
NatashaManagement.Preheating(true, true);

过滤预热

//如果存在 Dapper 主版本高于 12 的程序集,则不要将它加入缓存。
//传入排除方法
NatashaManagement.Preheating<NatashaDomainCreator>((asmName, name) => {
if (asmName.Name != null)
{
if (asmName.Name.Contains("Dapper") && asmName.Version!.Major > 12)
{
return true;
}
}
return false;
},true, truetrue);

也许您的环境过于复杂,从而遇到一些意外,请您精简代码之后,确保异常能够重现,提交 issue 给 Natasha。

智能编译

在预热后请参考以下代码

AssemblyCSharpBuilder builder = new();
var myAssembly = builder
.UseRandomDomain()
.UseSmartMode() //启用智能模式
.Add("public class A{ }")
.GetAssembly();

智能模式将合并 共享域与当前域的 元数据以及 Using, 并启用语义检查. 智能模式的 API 逻辑为:

.WithCombineReferences(item => item.UseAllReferences())
.WithCombineUsingCode(UsingLoadBehavior.WithAll)
.WithReleaseCompile()
.WithSemanticCheck();

可以参考[元数据管理与微调] 对 元数据 的合并行为进行微调。 可以参考[微调Using覆盖] 对 UsingCode 的合并行为进行微调。

其他案例

批量排除程序集

NatashaInitializer.Preheating((asmName, name) => {
if (name != null)
{
if (name.Contains("System"))
{
if (
name.Contains("Net") ||
name.Contains("Xml") ||
name.Contains("IO") ||
name.Contains("Reflection") ||
name.Contains("Threading") ||
name.Contains("Security") ||
name.Contains("Diagnostics") ||
name.Contains("Data") ||
name.Contains("Resources.") ||
name.Contains("Drawing") ||
name.Contains("Text") ||
name.Contains("Globalization") ||
name.Contains("Service") ||
name.Contains("Web") ||
name.Contains("Window") ||
name.Contains("ComponentModel")
)
{
//排除
return true;
}
return false;
}
if (name.Contains("Natasha"))
{
//加载
return false;
}
if (name.Contains("ConsoleApp3"))
{
//加载
return false;
}
}
return true;
}true, true);

根据版本排除程序集

该示例使用 AssemblyName 进行判断程序集名称及版本, 以下代码排除了 dapper 主版本号为 12 的程序集引用文件;

NatashaInitializer.Preheating((asmName, name) => {
if (asmName.Name != null)
{
if (asmName.Name.Contains("Dapper") && asmName.Version!.Major > 12)
{
return true;
}
}
return false;
});

减少程序集引用文件的加载,可以有效的控制内存涨幅.