30 votes

Pourquoi la couche d'interopérabilité COM pourrait-elle être 40 fois plus lente lorsque le client est compilé dans VS 2010 vs VS 2005?

Mon équipe travaille avec l'API COM d'une grande application de simulation. La plupart des fichiers de simulation de plusieurs centaines de méga-octets, et semblent être complètement chargé en mémoire lorsqu'ils sont ouverts.

La principale tâche que nous effectuons est une itération à travers tous les éléments dans le modèle d'objet de l'un fichier et ensuite de faire "quelque chose" à chaque élément.

Nous avons récemment déménagé notre base de code de .NET 2 dans de .NET 4 dans VS 2010 et ont vu l'itération de la vitesse de chute d'environ 40 fois (à partir de ~10 secondes environ 8 minutes). Nous avons réduit ce à la plus petite possible exemple de code (10 lignes); compilé ce dans VS 2005, l'exécuter, puis il ouvrit le projet dans VS 2010 et compilé, laissant le cadre 2 (nous utilisons le fabricant fourni COM interop assemblies).

En 2005, l'application de test est terminée en 10 secondes, en 2010, elle dure 8 minutes.

Ce pourrait être la cause?

Mise à JOUR

Le code est équivalent à:

var server = new Server();
var elements = server.Elements;
var elementCount = elements.Count;

for(int i = 0; i < elementsCount; ++i)
{
    var element = elements[i];
}

Ce code prend 40 fois plus de temps par rapport à 2010 de VS 2005.

Mise à JOUR 2

J'ai rationalisé que la seule raison que l'opération peut être considérablement plus lente dans l'un des cas que l'autre est que les données sont transférées différemment sur COM dans les différentes versions.

Nous avons enregistré la liaison des journaux pour les deux cas et c'est ce que nous avons trouvé; dans la version rapide de l'image native de CustomMarshalers est pas trouvé (ce sont la liaison journaux capturées par FUSLOGVW)

mscorlib

mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089.HTM

Rapide

LOG: Start binding of native image mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089.
LOG: Start validating native image mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089.
WRN: Native image does not satisfy request. Looking for next native image.
WRN: No matching native image found.

Lent

LOG: Start binding of native image mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089.
LOG: Start validating native image mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089.
LOG: Bind to native image succeeded.

CustomMarshalers

CustomMarshalers, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a

Rapide

LOG: Start binding of native image CustomMarshalers, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a.
LOG: Start validating native image CustomMarshalers, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a.
WRN: Native image does not satisfy request. Looking for next native image.
WRN: No matching native image found.

Lent

LOG: Start binding of native image CustomMarshalers, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a.
LOG: Start validating native image CustomMarshalers, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a.
LOG: Start validating all the dependencies.
LOG: [Level 1]Start validating native image dependency mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089.
LOG: Dependency evaluation succeeded.
LOG: [Level 1]Start validating IL dependency Microsoft.VisualC, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a.
LOG: Dependency evaluation succeeded.
LOG: Validation of dependencies succeeded.
LOG: Start loading all the dependencies into load context.
LOG: Loading of dependencies succeeded.
LOG: Bind to native image succeeded.
Native image has correct version information.
Attempting to use native image C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\CustomMarshalers\3e6deccf191ab943d3a0812a38ab5c97\CustomMarshalers.ni.dll.
Native image successfully used.

Donc, il semble que nous obtenons un gain important de performances lorsque l'image native est pas utilisé.

Pourquoi serait-ce lier d'échouer dans un cas, et de réussir dans un autre, et comment faisons-nous pour forcer l'application à ne pas utiliser l'image native?

Mise à JOUR 3

L'étrangeté se poursuit. Si j'exécute ce code dans VS 2010 dans une méthode de test à l'aide de la R# test runner, ou intégré de Visual Studio test runner alors il s'exécute à la vitesse rapide.

J'ai essayé d'emballage de ce code dans un ensemble, et puis le chargement dynamique et qui ne fait aucune différence.

2voto

cirrus Points 2354

Quand vous dites, "...même dans un STA threads de l'application sont...", qui n'est pas vraiment correct. Un thread peut choisir de mettre en place l'appartement de l'état avant qu'il accède à des objets COM, mais dans .NET si vous ne faites rien, ces fils va être implicitement MTA.

Le pool de threads est MTA. Il aura besoin d'être si vous pensez à ce sujet, car si elle était pleine de threads STA ce serait une merde thread pool de tout temps un thread essayé d'accéder à un objet créé à l'un des autres fils dans la piscine, il aurait besoin de triage.

Fil de discussion.SetApartmentState ne fonctionnera que par fil, par définition. Il n'a jamais pu affecter les autres threads (comme vous l'avez découvert). Les objets appartiennent à un appartement et d'un thread peut appartenir à un seul modèle de thread. Si le thread essaie de rendre visite à un objet avec un mauvais modèle, il aura besoin d'être muselé.

Si votre Serveur COM est marqué comme "à la fois", alors vous pouvez l'utiliser sans un proxy à partir d'un STA ou un thread MTA. Si c'est le cas, vous avez de la chance, et vous devez en créer un sur un thread MTA pour commencer (ou ont le pool de threads les threads de le faire).

Si vous créez sur un thread STA, même si (surtout si), toutes les autres threads sont STAs, ils seront TOUS de passer par un proxy, à moins que vous arrive d'appeler l'objet du thread qui a créé à l'origine.

Si votre serveur COM est mono-thread, alors vous aurez besoin pour vous assurer que vous l'appelez pas seulement à partir d'un thread STA, mais le thread STA qui crée d'abord, sinon vous serez rassemblés à travers un proxy.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X