【问题标题】:Preload all assemblies (JIT)预加载所有程序集 (JIT)
【发布时间】:2011-07-07 17:44:57
【问题描述】:

第一次加载一些繁重的 UI 屏幕时,我们受到了打击。我们的项目分为一个主要的可执行文件和几个 DLL 文件。 DLL 文件还可能包含第一次加载时速度较慢的 UI 屏幕。

有没有办法(在代码中)我们可以预加载所有引用的程序集以避免 JIT 编译命中?

我知道有一个工具叫NGen。是否可以在开发环境中操作 NGen,以便我们可以立即看到它的效果?但理想情况下,我们希望从代码中预加载引用的程序集。

将 C# .NET 3.5 与 DevExpress 一起用于我们的 UI 组件。

【问题讨论】:

  • 我认为这可以概括为:如何使引用许多程序集的程序加载更快。

标签: c# performance assemblies jit .net-assembly


【解决方案1】:

我个人发现,将预抖动放在“程序”中有助于某个应用程序,但这是一个特定情况的问题。

更重要的是wal's answer中的代码遇到抽象方法会崩溃,所以加了两行代码跳过抽象方法。

static Program()
{
    foreach (var type in Assembly.GetExecutingAssembly().GetTypes())
    {
        foreach (var method in type.GetMethods(BindingFlags.DeclaredOnly |
                            BindingFlags.NonPublic |
                            BindingFlags.Public | BindingFlags.Instance |
                            BindingFlags.Static))
        {
            if ((method.Attributes & MethodAttributes.Abstract) == MethodAttributes.Abstract|| method.ContainsGenericParameters)
            {
                continue;
            }
            System.Runtime.CompilerServices.RuntimeHelpers.PrepareMethod(method.MethodHandle);
        }
    }
    Console.WriteLine("jitted!");
}

【讨论】:

    【解决方案2】:

    您尝试/查看this了吗?

    也就是说,对要预 JIT 的每个程序集执行以下操作。

    static void PreJIT()
    {
        foreach (var type in Assembly.GetExecutingAssembly().GetTypes())
        {
            foreach (var method in type.GetMethods(BindingFlags.DeclaredOnly |
                                BindingFlags.NonPublic |
                                BindingFlags.Public | BindingFlags.Instance |
                                BindingFlags.Static))
            {
                System.Runtime.CompilerServices.RuntimeHelpers.PrepareMethod(method.MethodHandle);
            }
        }
    }
    

    【讨论】:

    • 我的测试表明,就 JITting 和优化而言,PrepareMethod 与调用方法不同。
    【解决方案3】:

    您可以在任何机器上使用 NGen - CLR 中没有“开发环境”的概念...当您使用它时,请确保实际使用了 NGen 处理的图像(请参阅 Native Image Generator (Ngen.exe) 获取说明并在文档中查找 FusLogVw 注释)。

    您还可以通过调用您希望运行的所有代码(如 Davita 建议的那样)来预 JIT,但您需要调用所有类的每个方法,这并不完全实用。

    您应该分析您的应用程序以查看实际花费的时间 - 它可能是从磁盘读取程序集,而不是 JITing 本身...您可以通过启动应用程序、查看表单、关闭应用和重复步骤。如果第二次运行快得多,则应用程序大部分时间都在从磁盘读取,而不是 JIT。

    【讨论】:

    • 阿列克谢,感谢您的 cmets。如果我们每次“第一次”加载表单时都关闭应用程序,它会很慢。随后的每一次加载表单的调用都发生得非常快。每次我们编译并运行应用程序时,结果都是一样的。
    • 这很可能是 JIT - NGEN 应该提供帮助。
    【解决方案4】:

    看看NGen。另一种选择是使用ILMerge 将所有程序集合并为一个。每当我使用 ILMerge 时,我都会添加一个构建后命令,以便它自动发生。另一种选择(未经测试)是,如果您不介意更长的启动时间,您可以在每个程序集的开头手动调用 Assembly.Load()。

    【讨论】:

    • 我们已经研究了 ILMerge,当我们发布到生产环境中时,会将所有程序集合并到一个更大的可执行文件中。我想真正的问题是我们能否在开发环境中看到 NGEN 的好处?
    • 加载程序集不会 JIT 大多数方法(如果有)。它将强制磁盘访问时间/程序集加载本身更早发生。
    • 使用Assembly.Load() 不会有任何帮助。看看my question
    【解决方案5】:

    您可以只创建位于外部程序集中的类的实例。只需在有限范围内调用构造函数(我的意思是在函数内声明变量。它不应该是全局变量,因为它会延迟 GC 处理该实例)。这将加载程序集,编译它并缓存它。您甚至可以在后台线程中执行此操作,以便主线程保持响应。

    【讨论】:

    • 这不会 JIT 大部分代码(只有你会明确调用的那个)。
    猜你喜欢
    • 1970-01-01
    • 2011-03-02
    • 1970-01-01
    • 1970-01-01
    • 2010-10-02
    • 1970-01-01
    • 2011-06-21
    • 2023-04-09
    • 1970-01-01
    相关资源
    最近更新 更多