我正在将小脚本嵌入到c#应用程序中。
为了提高性能,我在应用程序启动时编译它们。CompiledCode.Execute在第一次迭代中需要很长时间
public CompiledCode CompileScript(string script)
{
return engine.CreateScriptSourceFromString(script).Compile();
}
CompiledCode实例然后存储在一个字典中,以便稍后可以重用它们。
当时间已经到了执行它们,我使用类似:
result = code.Execute(scope);
凡范围是一个简单的辅助类保持了ScriptScope
一个实例。
这个范围设置,以便提供给脚本变量和组件正确添加创建助手的实例时:
if (variables != null)
{
scope = engine.CreateScope(variables);
}
else
{
scope = engine.CreateScope();
}
if (assemblies != null)
{
assemblies.ForEach(a => scope.Engine.Runtime.LoadAssembly(a));
}
基本上,组件的列表传递给助手类的构造函数,并在各个地方重用助手类的实例。 (不是静态类,因为我确实需要针对特定场景的多个帮助程序实例,但是在这个问题的上下文中,我们正在讨论单个实例)
在普通PC上使用此操作时,编译/运行代码是可忽略的。
但是,我在RaspberryPI
上运行这个程序,并注意到第一次执行特定脚本时,需要很长时间。 (对于2行脚本容易达到40秒)
后续执行相同CompiledCode
实例的执行速度非常快(200毫秒)。
所以我有已编译的代码(奇怪的是,第一次编译也非常快),但在给定的CompiledCode
实例上首次调用Execute()需要很长时间。
现在我想知道,Execute()
第一次做什么,并且有没有一种方法可以在不实际执行代码的情况下在早期执行任何操作? 在编译和实际运行代码之间似乎还有一个额外的步骤。
我想也许它的相关的事实,我重用了
辅助类中定义的范围,当然,如果我只使用默认范围上执行
我没有任何变量和组装引用。
更新:
在树莓派跑这意味着我使用单声道。
更具体地说 单声道2.10.8.1(Debian 2.10.8.1-8)
我无法更新单声道,因为我依赖的是一个非常特定的MonoGame
版本,该版本只适用于编写本文时的这个Mono版本。
您是否尝试过使用性能分析器来查看它?有没有例外?你看过哪些程序集正在加载/ JIT和需要多长时间? – 2013-03-20 09:28:24
不,挂接分析器非常困难,它只发生在运行在Raspberry上时,所以没有调试器,单声道分析器也没有帮助我。奇怪的是,它每CompiledCode只发生一次,并且组装/变量加载只发生一次,而不是CompiledCode的每个实例,所以它真的是第一个执行需要这么长时间。另一种方法是我使用MEF来支持插件而不是脚本 – TimothyP 2013-03-20 09:54:37
Compile()方法生成IL。然后必须将其转换为机器码。这需要做一次,你正在测量需要多长时间。单声道没有最奇怪的抖动,但40秒是相当长的时间。足够长的时间来怀疑某种网络问题,它大致匹配默认的tcp/ip连接超时。 – 2013-03-20 12:32:46