c# - todas - ¿Por qué la capa de interoperabilidad COM podría ser 40 veces más lenta cuando el cliente se compila en VS 2010 vs VS 2005?
todas las versiones de office (2)
Cuando dices: "... incluso en una aplicación STA, los hilos son ...", eso no es realmente correcto. Un subproceso puede elegir configurar su estado de apartamento antes de acceder a cualquier objeto COM, pero en .NET, si no hace nada, esos subprocesos serán implícitamente MTA.
El threadpool es MTA. Tendrá que serlo si lo piensa, porque si estuviera lleno de subprocesos STA sería un conjunto de subprocesos de mala calidad como siempre que un subproceso intentara acceder a un objeto creado en uno de los otros subprocesos del conjunto que necesitaría marshalling
Thread.SetApartmentState solo funcionará por hilo por definición. Nunca podría afectar a otros hilos (como has descubierto). Los objetos pertenecen a un apartamento y un subproceso puede pertenecer a un solo modelo de subprocesamiento. Si el subproceso intenta visitar un objeto con un modelo que no coincide, será necesario calcularlo.
Si su servidor COM está marcado como "ambos", entonces puede usarlo sin un proxy desde un subproceso STA o MTA. Si ese es el caso, tienes suerte, y deberías crearlo en un subproceso MTA para comenzar (o hacer que los subprocesos de subprocesos lo hagan).
Si lo crea en un subproceso STA, incluso si (especialmente si) todos sus otros subprocesos son STA, TODOS pasarán por un proxy, a menos que llame al objeto desde el subproceso que lo creó originalmente.
Si su servidor COM tiene un solo hilo, deberá asegurarse de que lo llama no solo desde un hilo STA, sino que el hilo STA que primero lo crea, de lo contrario, se le solicitará un proxy.
Mi equipo trabaja con la API COM de una aplicación de simulación grande. La mayoría de los archivos de simulación se ejecutan en cientos de megabytes y parece que se cargan completamente en la memoria cuando se abren.
La tarea principal que realizamos es iterar a través de todos los elementos en el modelo de objeto del archivo y luego hacer "algo" a cada elemento.
Recientemente hemos movido nuestra base de código de .NET 2 a .NET 4 en VS 2010 y hemos visto caer la velocidad de iteración aproximadamente 40 veces (de ~ 10 segundos a aproximadamente 8 minutos). Hemos reducido esto al ejemplo de código más pequeño posible (10 líneas o menos); compiló esto en VS 2005, ejecútelo y luego abrió el proyecto en VS 2010 y compiló, dejando el marco como 2 (estamos utilizando los ensamblajes de interoperabilidad COM suministrados por el fabricante).
En 2005, la aplicación de prueba se completa en 10 segundos, en 2010 toma 8 minutos.
¿Qué podría estar causando esto?
ACTUALIZAR
El código es equivalente a:
var server = new Server();
var elements = server.Elements;
var elementCount = elements.Count;
for(int i = 0; i < elementsCount; ++i)
{
var element = elements[i];
}
Este código tarda 40 veces más en ejecutarse a través de VS 2010 que VS 2005.
ACTUALIZACIÓN 2
Racionalicé que la única razón por la que la operación puede ser dramáticamente más lenta en un caso que en el otro es que los datos se transfieren de manera diferente a través de COM en las diferentes versiones.
Registramos los registros de enlace para ambos casos y esto es lo que encontramos; en la versión rápida no se encuentra la imagen nativa de CustomMarshalers (estos son los registros de enlace capturados por FUSLOGVW)
mscorlib
mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089.HTM
Rápido
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.
Lento
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
Rápido
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.
Lento
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.
Así que parece que obtenemos un gran aumento de rendimiento cuando no se usa la imagen nativa.
¿Por qué este enlace falla en un caso y tiene éxito en otro, y cómo forzamos a la aplicación a no usar la imagen nativa?
ACTUALIZACIÓN 3
La rareza continúa. Si ejecuto este código en VS 2010 en un método de prueba usando el corredor de prueba R #, o el corredor de prueba incorporado de Visual Studio, entonces se ejecuta a la velocidad rápida.
He intentado envolver este código en un ensamblaje y luego cargarlo dinámicamente y eso no hace ninguna diferencia.
Era una especie de tiro largo. Me alegro de poder ayudar.
La concordancia entre MTA y STA (modelo de subprocesamiento) es realmente importante cuando se realizan muchas llamadas distintas a cualquier objeto COM. Una directiva [STAThread]
en la parte superior de un método es una forma de estar seguro del modelo de subprocesos para cada llamada en ese método.
Parece que Thread.SetApartmentState(ApartmentState.STA)
funcionará para un subproceso completo, pero aparentemente no para los subprocesos de agrupación de subprocesos.