2013-11-26 7 views
0

Когда я создаю объект класса, который реализует интерфейс через Activator.CreateInstance или с помощью ключевого слова new, скорость выполнения явно отличается. Тип создания, который я использую, сначала является более быстрым для остальной части выполнения программы. Я написал следующее "Performance-Test":.NET 2.0: Activator.CreateInstance (...) vs new: Почему скорость выполнения зависит от последовательности?

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 -модификатор и возвращает «Удаленный» вместо «Локальный»):

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 -project перед Plugin -project.

Теперь программа-выход для этого тест-блока

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. Что я могу сделать, чтобы получить такое же исполнение при каждом исполнении?

С уважением,

Matthias

ответ

0

Похоронен в следующей статье является причиной:
A curious subtlety about how CLR does interface dispatch on array types

Конкретный текст представляет интерес следующее:

Наш интерфейс логика отправки имеет важную оптимизацию, где ДЛЯ КАЖДОГО ЗВОНОК E, он явно проверяет одну конкретную цель, и если это не удается, происходит медленный поиск таблицы хэшей, и если этот поиск не удается, вернитесь к дорогостоящему поиску. Таким образом, для сайтов звонков, которые, как правило, отправляются в один пункт назначения, очень быстро, и вызывать сайты, которые идут на многие цели, вы получаете хорошую, но не такую ​​высокую производительность.

Оптимизация сайта вызова инициализируется в соответствии с конкретным типом первого объекта, который появился.

Вы должны иметь возможность произвести справедливое сравнение, заменив интерфейс IPlugin в своем тесте классом PluginBase.

+0

спасибо. Вывод из класса приводит к более четкому (и чуть более быстрому) результату: 'SpeedTest of« Local »: 00: 00: 22.2333277' ' SpeedTest of «Plugin»: 00: 00: 19.1486855' – Matthias