.NET 2.0:Activator.CreateInstance(...)vs new:为什么执行速度依赖于顺序?

时间:2013-11-26 13:54:44

标签: c# .net performance plugins activator

当我创建一个通过Activator.CreateInstancenew关键字实现接口的类的对象时,执行速度明显不同。我首先使用的创建类型对于程序执行的其余部分来说是更快的。我写了以下“性能测试”:

static private void SpeedTest(IPlugin plugin)
{
    Console.Write("SpeedTest of \"" + plugin.Name + "\": ");

    Stopwatch sw = new Stopwatch();

    int workingNumber = 0;

    sw.Start();

    for (int i = 0; i < 2147483647; i++)
    {
        plugin.Add(ref workingNumber);
        plugin.DSub(ref workingNumber);
        plugin.Add(ref workingNumber);
    }

    sw.Stop();

    Console.WriteLine(sw.Elapsed.ToString());
}

我通过以下方式加载实现IPlugin的类的实例:

static void Main(string[] args)
{
    IPlugin pluginInstance = null;
    IPlugin localInstance = new LocalPlugin();

    Assembly plugin = Assembly.LoadFile("Path\\Plugin.dll");

    Type pluginInterface = typeof(IPlugin);

    foreach (Type type in plugin.GetTypes())
        if (pluginInterface.IsAssignableFrom(type))
            pluginInstance = (IPlugin)Activator.CreateInstance(type);

    SpeedTest(localInstance);
    SpeedTest(pluginInstance);
    SpeedTest(localInstance);
    SpeedTest(pluginInstance);
}

IPlugin看起来像:

public interface IPlugin
{
    string Name { get; }

    void Add(ref int number);
    void DSub(ref int number);
}

“本地”插件(以及来自Plugin.dll的远程插件,除了它有一个public - 修饰符并且返回“远程”而不是“本地”)时看起来像:< / p>

class LocalPlugin : IPlugin
{
    public string Name
    {
        get { return "Local"; }
    }

    public void Add(ref int number)
    {
        number++;
    }

    public void DSub(ref int number)
    {
        number -= 2;
    }
}

以下是两个项目供您下载:ZIP-File with example projects

您需要在PluginHost - 项目之前编译Plugin - 项目。

现在这个测试块的程序输出

SpeedTest(pluginInstance);
SpeedTest(localInstance);
SpeedTest(pluginInstance);
SpeedTest(localInstance);

是:

SpeedTest of "Plugin": 00:00:25.9785649
SpeedTest of "Local": 00:00:38.8875138
SpeedTest of "Plugin": 00:00:25.8757588
SpeedTest of "Local": 00:00:38.5222134

如果我将第一行移动到最后一个位置:

SpeedTest(localInstance);
SpeedTest(pluginInstance);
SpeedTest(localInstance);
SpeedTest(pluginInstance);

我得到以下输出:

SpeedTest of "Local": 00:00:26.1881051
SpeedTest of "Plugin": 00:00:38.9942815
SpeedTest of "Local": 00:00:25.9634257
SpeedTest of "Plugin": 00:00:38.6881451

结论:我首先使用的实例化类型比第二个快。此行为是方法独立的。

问题:

  1. 为什么会这样?
  2. 如何才能在每次执行中获得相同的性能?
  3. 的问候,

    的Matthias

1 个答案:

答案 0 :(得分:0)

埋在以下文章中的原因是:
A curious subtlety about how CLR does interface dispatch on array types

感兴趣的具体文字如下:

  

我们的接口调度逻辑有一个重要的优化,其中FOR EACH CALL SITE,它显式地检查一个特定目标,如果失败,则执行较慢的哈希表查找,如果该查找失败,则回退到昂贵的查找。因此,对于往往到达一个目的地的呼叫站点而言,它非常快,并且呼叫到达许多目标的站点,你会变得很好,但性能却不是很好。

根据出现的第一个对象的具体类型初始化呼叫站点优化。

您应该能够通过将测试中的IPlugin接口替换为PluginBase类来产生公平的比较。