c# - 编译 C# 脚本很慢

标签 c# .net scripting codedom

我有一个使用 C# 编写的“脚本”的应用程序,在启动时使用 C# CodeDomProvider 进行编译。加载几十个甚至超过 170 个脚本并不是什么大问题,我编译它们,然后将程序集保存到缓存文件夹中以供下次启动。对于 170 个脚本,此初始编译大约需要 1.5 分钟。

但是,当我尝试加载超过 1000 个脚本时,需要一个多小时才能编译全部脚本。我添加了一个秒表,发现每个脚本的加载时间都比之前的要长一点,在 170 个文件的情况下,它从第一个文件的约 150 毫秒到最后一个文件的 > 650 毫秒,每个文件都一点一点地增加文件。

我知道,通过将脚本合并到一个大文件中,我通常可以大大减少加载时间,但出于多种原因,如果我可以单独编译它们,我会更喜欢它:/这使得重新加载它们变得简单快捷,我不必担心在发生变化时重新编译整个脚本文件夹,我可以轻松地给出编译进度的进度条等。

现在我的问题是,这里出了什么问题?为什么每个文件的编译时间会随着时间的推移而增加?我可以为此做点什么吗?

编辑

我会按照评论中的要求尝试提供更多信息。

正如我所说,我正在使用 C# CodeDomProvider 编译每个脚本,基本上是循环中的以下内容,对于我当前的 171 个脚本文件中的每一个,每个文件都包含我在汇编后实例化的一个或多个类已创建:

var provider = System.CodeDom.Compiler.CodeDomProvider.CreateProvider("CSharp"); ;
var parameters = new System.CodeDom.Compiler.CompilerParameters();
parameters.ReferencedAssemblies.AddRange(AppDomain.CurrentDomain.GetAssemblies().Where(a => !a.IsDynamic).Select(a => a.Location).ToArray());
parameters.GenerateExecutable = false;
parameters.GenerateInMemory = false;
parameters.OutputAssembly = tmpFileName + ".compiled";
parameters.TreatWarningsAsErrors = false;
parameters.WarningLevel = 0;
var results = provider.CompileAssemblyFromFile(parameters, tmpFileName);
asm = results.CompiledAssembly;

我使用 CS-Script 得到了相同的结果,它做了类似的事情。

asm = CSScript.LoadWithConfig(tmpFileName, null, debug, CSScript.GlobalSettings, "/warnaserror- /warn:0");

创建的程序集随后将保存到缓存文件夹中。当脚本文件比程序集旧时,将使用保存的程序集,因此我不必再次编译它。

当你坐在它前面,看着进度条前进得越来越慢时,随着时间的推移,它变得越来越慢,这一点变得很明显,所以我在上面的代码周围添加了一个简单的秒表调用,StartNew, Stop, Elapsed ,没什么花哨的。结果反射(reflect)了我在进度条上看到的情况,每个附加文件都会增加编译时间。

timer.Restart();

// compile as shown above

timer.Stop();
Console.WriteLine(asm.Location + ": " + timer.Elapsed);

当然,文件之间存在细微的差异是可以预料的,具体取决于它们的大小和复杂程度,但脚本的大小和复杂性通常或多或少相同,而且我正在见证持续的增长随着时间的推移。

Temp\tmpDDD7.tmp.compiled: 00:00:00.1389177
Temp\tmpDE74.tmp.compiled: 00:00:00.1327150
...
Temp\tmpE156.tmp.compiled: 00:00:00.1719746
Temp\tmpE213.tmp.compiled: 00:00:00.1431011
...
Temp\tmpF05C.tmp.compiled: 00:00:00.1696297
Temp\tmpF118.tmp.compiled: 00:00:00.1739564
...
Temp\tmpF7D5.tmp.compiled: 00:00:00.1824292
Temp\tmpF891.tmp.compiled: 00:00:00.1819889
...
Temp\tmp29F1.tmp.compiled: 00:00:00.2912163
Temp\tmp2B2B.tmp.compiled: 00:00:00.2909096
...
Temp\tmp362F.tmp.compiled: 00:00:00.3161408
Temp\tmp3773.tmp.compiled: 00:00:00.3170768
...
Temp\tmpA4C9.tmp.compiled: 00:00:00.5457990
Temp\tmpA6FC.tmp.compiled: 00:00:00.5460514

最佳答案

编译变得越来越慢的原因是每个创建的程序集都被添加为对所有后续脚本文件的引用。在第一个文件上可能有 10 个引用,在第二个文件上可能有 11 个引用,在第三个文件上可能有 12 个引用,依此类推。引用文献越多,编译所需的时间就越长。这就是下面一行的作用,也是 CS-Script 默认情况下所做的。

parameters.ReferencedAssemblies.AddRange(AppDomain.CurrentDomain.GetAssemblies().Where(a => !a.IsDynamic).Select(a => a.Location).ToArray());

不幸的是,我希望脚本能​​够相互引用,所以我现在必须想出一个引用系统。但至少我知道问题出在哪里。也许我会尝试自动化它,记住在哪个程序集中可以找到哪些类型,以便自动引用它们。

关于c# - 编译 C# 脚本很慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31208684/

相关文章:

c# - 比较 char 忽略大小写的正确方法是什么?

c# - 无法使用 Google API 更新 GTM 变量

linux - elif 的语法错误

Python 网络/cidr 计算

Javascript 作为命令行可调用脚本语言

c# - 泛型——需要说明

c# - Dijkstra 算法扩展了额外的限制变量

c# - 禁止 WCF 客户端证书和用户名凭据

c# - 在哪里可以找到 GetMemberInfo

c# - 用一维索引访问多维数组