, что кажется крайне неэффективным для такой фундаментальной критической характеристики производительности
Как часто, по вашему мнению, делегаты присоединяются к событиям (или объединяются в другое время)?
Например, в приложении Windows Forms это может происходить довольно редко - в основном при настройке формы, по большей части ... в этот момент происходят гораздо более тяжелые вещи, чем в MulticastDelegate.CombineImpl
.
Что делает очень часто, так это то, что делегаты вызываются ... например, для каждого элемента в каждой проекции или предикате (и т. Д.) В запросе LINQ. Это действительно важный бит производительности, IMO.
Я также не уверен, что этот код настолько неэффективен, как вы думаете.Он использует тот же подход, что и ArrayList
, в плане создания массива большего размера, чем необходимо, чтобы заполнить его по мере необходимости.Будет ли связанный список более эффективным?Возможно, в некоторых терминах - но в равной степени это будет менее эффективным с точки зрения локальности и уровней косвенности.(Поскольку каждый узел должен быть новым объектом, который сам содержит ссылку на делегат, перемещение по списку может привести к тому, что в память будет добавлено больше страниц, чем массив ссылок.)
РЕДАКТИРОВАТЬ:быстрый микробенчмарк (со всеми обычными предостережениями) вот код для выполнения заданного количества итераций объединения заданного числа делегатов:
using System;
using System.Diagnostics;
class Test
{
const int Iterations = 10000000;
const int Combinations = 3;
static void Main()
{
// Make sure all paths are JITted
Stopwatch sw = Stopwatch.StartNew();
sw.Stop();
Action tmp = null;
for (int j = 0; j < Combinations; j++)
{
tmp += Foo;
}
sw = Stopwatch.StartNew();
for (int i = 0; i < Iterations; i++)
{
Action action = null;
for (int j = 0; j < Combinations; j++)
{
action += Foo;
}
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
}
static void Foo()
{
}
}
Некоторые результаты на моем компьютере, все с 10 000 000 итераций:
5 делегатов: около 5,8 секунд
4 делегата: около 4,3 секунд
3 делегата: около 3,2 секунд
2 делегата: около 1,4 секунд
1 делегат: около 160 мс
(Все тесты выполняются несколько раз; приведенные выше примеры являются просто примерами, которые казались достаточно репрезентативными. Я не взял среднее значение или что-то в этом роде.)
Учитывая вышеприведенные результаты, я подозреваю, что любые пути, даже в комбинации, тяжелыеWPF, к которому присоединяется только один делегат , будет невероятно быстрым.Они значительно замедляются, начиная с 1-2, а затем постепенно ухудшаются (но с гораздо меньшей пропорциональной разницей, чем случай 1-2).