2013-11-28 2 views
4

У меня есть утилита, предназначенная для передачи объектов вокруг нашей системы. Поскольку это многопоточная среда, утилита делает глубокую копию каждого передаваемого им объекта, чтобы предотвратить любые проблемы безопасности потоков. Я работаю над переходом нашей системы на использование неизменяемых объектов для устранения необходимости в этой копии. Мне интересно, какой лучший (самый быстрый) способ обнаружить, что объект неизменен?Простой способ обнаружения неизменяемости?

Моя первая мысль состояла в том, чтобы просто подобрать атрибут, который мы наносим на все наши неизменные объекты (MessageAttribute). Как вы можете видеть из приведенного ниже профиля производительности, он получает довольно сильный удар (примерно 10 раз для выполнения всех моих других проверок).

enter image description here

Как еще можно обнаружить мои immutables проходя через? Я могу просто сделать сравнение typeof(), которое выглядит более реалистичным, но это кажется довольно громоздким, и это будет чертовски поддерживать, поскольку мы постоянно добавляем больше неизменяемых.

EDIT: Я забыл упомянуть, что булевы значения переработаны из в переменных с целью профилирования, в действительности, выражения кто есть результат сохраняется в isDefined на самом деле в else if заявления, так буду ударяться о В 10 раз меньше, чем показано в этом профиле (меня больше беспокоит среднее время выполнения, чем абсолютное время выполнения).

ответ

1

Я закончил реализацию набора Hash, который инициализируется в статическом конструкторе и получает все типы, которые я хочу передать.

private static HashSet<Type> m_PassableTypes; // 


static SynthesisExtensions() { // 
    m_PassableTypes = new HashSet<Type>(); 
    foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) { 
     foreach (Type type in assembly.GetTypes()) { 
      if (type.IsValueType || type == typeof (string) || type.Module.Name == "FSharp.Core.dll" || 
       type.IsDefined(typeof (MessageAttribute), false)) { 
       m_PassableTypes.Add(type); 
      } 
     } 
    } 
} 

Это позволяет мне выполнить очень быстрый поиск HashSet, который является более эффективным.

Type type = instance.GetType(); 

    if (m_PassableTypes.Contains(type)) { 
     // cache the self-reference 
     referenceCache.Add(instance, instance); 
     // return the value itself 
     return instance; 
    } 

Спасибо за помощь!Я бы приветствовал любые мысли об этом решении

4

Сделайте интерфейс (например, IImmutable) и используйте его на всех своих неизменяемых классах.

Вам нужно только проверить этот интерфейс с помощью typeof(), чтобы обнаружить неизменяемый.

typeof() - это проверка времени компиляции, поэтому у вас нет удара производительности.

3

Вы используете isDefined только в ветке else, которая поражает 10x меньше, чем then. Вычислите значение только при необходимости. Это должно сократить его стоимость на 10 раз.

Помимо этого вы можете ввести кэш для вычисления. Есть, вероятно, очень мало типов, которые вы когда-либо проверяли, поэтому кеш был бы небольшим.

+0

Я думал, что любой достойный компилятор может оптимизировать это (ну, собственно, потому, что компилятор должен _know_ System.Type неизменен, а его методы не имеют побочного эффекта) ... У меня возникает соблазн профилировать это в выпуске! –

+0

Спасибо за ответ, я отредактировал свой вопрос, чтобы уточнить, что я действительно это сделал, я просто реорганизовал его, чтобы упростить мое профилирование. – GBleaney

+0

@Adriano. NET JIT не приличный ... – usr

2

Я бы просто кэшировал результат, так как атрибуты типа не будут меняться.

public class SomeHelperClass 
{ 
    private static readonly ConcurrentDictionary<Type, bool> messageAttributesCache = new ConcurrentDictionary<Type, bool>(); 
    private static readonly Type messageAttributeType = typeof(MessageAttribute); 

    public static bool IsMessageAttributeDefined(Type type) 
    { 
     bool isDefined = false; 
     if (messageAttributesCache.TryGetValue(type, out isDefined)) 
     { 
      return isDefined; 
     } 
     isDefined = type.IsDefined(messageAttributeType, false); 
     return messageAttributesCache[type] = isDefined; 
    } 
} 

Затем используйте

bool isDefined = SomeHelperClass.IsMessageAttributeDefined(type); 

Вы можете сделать решение универсальным, я просто дать некоторое представление это какой-то быстрый уродливый код. Тем не менее, это будет лучше.

Смежные вопросы