Delphi:加速接口插件(DLL)的加载

时间:2014-02-21 00:28:48

标签: multithreading performance delphi dll interface

几天前,我在SO成员的帮助下创建了一个安全的插件系统,使用接口在主应用程序和dll之间进行通信。这解决了我在访问冲突和内存泄漏方面遇到的一些问题,现在一切正常,没有错误或崩溃。

所以,我一直在为这个项目创建一些长期的插件,这引出了另一个问题:速度

我现在正在做的是,当主应用程序启动时,将所有dll加载到遵循确定名称模式的特定文件夹中。

我用来加载它们的代码如下:

if FindFirst(cfg.ExePath+cPathPlugins+'\np*.npl', faAnyFile, SR)<>0
   then Exit; // npl files are in fact renamed dll's

PluginHost := TPluginHost.Create as IPluginHost;
Plugins    := TObjectList<TPluginInfo>.Create(True);

repeat
  if (SR.Attr <> faDirectory)
  then begin
    dll := LoadLibrary(PChar(cfg.ExePath+cPathPlugins+SR.Name));
    if dll<>0
    then begin
      @PluginInit := GetProcAddress(dll, 'PluginInitialize');
      if Assigned(PluginInit)
      then begin
        Plugin := TPluginInfo.Create;
        try
          Plugin.Dll  := dll;
          Plugin.Intf := PluginInit(PluginHost);
          Plugins.Add(Plugin);
        except
          Plugin.Free;
        end;
      end
      else FreeLibrary(dll);
    end;
  end;
until FindNext(SR)<>0;
System.SysUtils.FindClose(SR);

这段代码需要大约45秒才能加载7个插件。这些dll都没有初始化代码,PluginInitialize只传递主机接口并检索插件接口。

我的问题是:

  1. 接口上的方法数量是否会影响此时的加载速度?我不相信,但想确认一下。

  2. 这个加载时间是否会以某种方式被削减,同时仍会在启动时加载它们?

  3. 我想到了一个替代方案,将插件的名称加载到数据库中并仅在首次使用时加载dll本身,但我不想应用它,因为其中一些插件必须自动运行在应用程序执行期间完成某些事件,而不仅仅是按需菜单选项。

    我想也许这可以在后台加载插件,在不同的线程上完成,但我不知道这是否会带来任何风险,因为我从未使用过线程。 我认为使用线程的主要风险是当一个人试图访问被另一个修改的变量时,这是对的吗? 在这种情况下,我认为这不会发生,因为在插件加载之后,插件名称(使用其中一种方法)并将其添加到TButtonGroup中,这是在开始搜索dll之前创建的。

    你相信这会是一个很好的解决方案吗? 如果没有,您可以指出我的其他选择吗?

1 个答案:

答案 0 :(得分:3)

你的问题是DLL很大。您需要使用运行时包创建DLL。这样,代码只加载一次。每个DLL将包含相同代码的副本。 LoadLibrary将加载DLL并调用每个DLL的初始化代码。这意味着程序包X将链接到使用它的每个插件中,并在加载每个插件时进行初始化。 (校正

对于独立的EXE文件,取消运行时包非常棒。它使部署更加简单。当您想要开始使用插件系统时,最好切换到包含运行时包的系统。

这并不意味着您需要将每个运行时包分开。例如,如果您只在主应用程序或单个插件中使用Dev Express控件,那么您可以让Delphi将该软件包编译到App / DLL中。

要更改要保留的运行时软件包以及要包含在项目中的哪些软件包,请转到项目选项中的“软件包运行时软件包”页面。有一个复选框,允许您选择与运行时包链接。下面是一个文本框。在此文本框中,您可以指定要保持分开的包的名称。