Domanda

I have a utility that is designed to pass objects around our system. Because it is a multithreaded environment, the utility makes a deep copy of each object it passes to prevent any thread safety issues. I'm working on transitioning our system to use immutable objects to eliminate the need for this copy. I'm wonder what is the best (fastest) way to detect that the object is immutable?

My first thought was to just to pick up on the attribute that we put on all our immutable objects (MessageAttribute). As you can see from the performance profile below, it takes quite a hit (roughly 10x the time to execute as all my other checks).

enter image description here

How else can I detect my immutables passing through? I can just do a typeof() comparison, which appears way more performant, but this seems pretty unwieldy, and it will be hell to maintain as we add more immutables all the time.

EDIT: I forgot to mention that the boolean values are refactored out into variables for the purpose of profiling, in reality, the expressions who's result is stored in isDefined is actually in the else if statement, so would be hit about 10x less that shown in this profile (I'm more concerned with the average execution time than the absolute execution time though).

È stato utile?

Soluzione 4

I ended up implementing a Hash set that is initialized in the static constructor and gets all the type I want to pass trough.

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);
            }
        }
    }
}

This allows me to then perform a really fast HashSet look up which is way more performant.

    Type type = instance.GetType();

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

Thanks for all the help! I'd welcome any thoughts on this solution

Altri suggerimenti

Make an interface (eg. IImmutable) and use it on all your immutable classes.

You only have to check for this interface with typeof() to detect an immutable.

typeof() is a compile time check, so you have no performance hit.

You are using isDefined only in the else branch which is hit 10x less then the then branch. Only compute the value when needed. That should cut its cost by 10x.

Apart from that you could introduce a cache for the computation. There are probably very few types that you ever inspect, so the cache would be small.

I'd just cache the result since type's attributes are not going to change.

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;
    }
}

Then use

bool isDefined = SomeHelperClass.IsMessageAttributeDefined(type);

You may make the solution generic, I just give some idea this is some quick ugly code. This will be better performing though.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top