Componentes de Windows Runtime y optimización de la interoperabilidad

Cree aplicaciones de Windows que usen componentes de Windows e interactúen con los tipos administrados y nativos, al mismo tiempo que evitan problemas de rendimiento de la interoperabilidad.

Procedimientos recomendados de interoperabilidad con los componentes de Windows Runtime

Si no tiene cuidado, el uso de componentes de Windows Runtime puede afectar considerablemente al rendimiento de la aplicación. En esta sección se describe cómo conseguir un buen rendimiento cuando la aplicación usa componentes de Windows Runtime.

Introducción

La interoperabilidad puede afectar considerablemente al rendimiento y es posible que la estés usando sin darte cuenta. Windows Runtime controla gran parte de la interoperabilidad para que pueda ser más productivo y para que pueda volver a usar el código escrito en otros lenguajes. Le animamos a que aproveche todo lo que Windows Runtime le ofrece, pero tenga en cuenta que esto puede afectar al rendimiento. En esta sección se describen algunos métodos que puedes usar para reducir el efecto de la interoperabilidad en el rendimiento de tu aplicación.

Windows Runtime cuenta con una biblioteca de tipos a los que se puede obtener acceso en cualquier lenguaje en el que se pueda escribir una aplicación de la Plataforma universal de Windows. Los tipos de Windows Runtime en C# o Microsoft Visual Basic se usan del mismo modo que los objetos de .NET. No es necesario que realice llamadas del método de invocación de plataforma para obtener acceso a los componentes de Windows Runtime. Esto facilita mucho la escritura de las aplicaciones, pero es importante que sepas que puede haber más interoperabilidad de la que esperas. Si un componente de Windows Runtime está escrito en un lenguaje diferente de C# o Visual Basic, al usar ese componente estará cruzando el límite de la interoperabilidad. Cruzar los límites de interoperabilidad puede afectar al rendimiento de las aplicaciones.

Cuando desarrolle una aplicación de la Plataforma universal de Windows en C# o Visual Basic, los dos conjuntos más comunes de API que se usan son las API de Windows Runtime y las API de .NET para aplicaciones para UWP. En general, los tipos proporcionados por Windows que se basan en Windows Runtime en espacios de nombres que comienzan con "Windows." y los tipos .NET están en espacios de nombres que comienzan con "System."; sin embargo, existen excepciones. Los tipos de .NET para aplicaciones para UWP no necesitan interoperabilidad cuando están en uso. Si ve que el rendimiento es deficiente en un área que usa Windows Runtime, puede usar .NET para aplicaciones para UWP para mejorar el rendimiento.

Nota: La mayoría de los componentes de Windows Runtime que se incluyen en Windows 10 se implementan en C++. Por eso, cuando los usa desde C# o Visual Basic, cruza los límites de la interoperabilidad. Como siempre, antes de modificar el código, asegúrese de evaluar la aplicación para averiguar si el uso de componentes de Windows Runtime afectará al rendimiento.

En este tema, cuando hablamos de "componentes de Windows Runtime", nos referimos a los componentes de Windows Runtime que se escriben en un lenguaje diferente de C# o Visual Basic.

 

Recuerde que, cada vez que obtiene acceso a una propiedad o llama al método de un componente de Windows Runtime, incurre en un coste de interoperabilidad. De hecho, crear un componente de Windows Runtime es más costoso que crear un objeto de .NET. Esto se debe a que Windows Runtime debe ejecutar un código que realiza una transición del lenguaje de la aplicación al lenguaje del componente. Además, si pasas datos al componente, estos deben convertirse entre tipos administrados y no administrados.

Uso de los componentes de Windows Runtime de forma eficaz

Si se da cuenta de que necesita mejorar el rendimiento, puede asegurarse de que el código usa los componentes de Windows Runtime con la mayor eficacia posible. En esta sección se describen algunas sugerencias para mejorar el rendimiento al usar componentes de Windows Runtime.

Hace falta una cantidad considerable de llamadas en un período breve para que se aprecien los efectos sobre el rendimiento. Una aplicación bien diseñada que encapsula llamadas a los componentes de Windows Runtime desde la lógica de negocios y otros códigos administrados no debería implicar un gran costo de interoperabilidad. Pero si las pruebas indican que usar componentes de Windows Runtime afecta al rendimiento de la aplicación, las sugerencias que se describen en esta sección pueden ayudarle a mejorar el rendimiento.

Considere la posibilidad de usar tipos que proporcione .NET para aplicaciones para UWP

Hay ciertos casos en los que puede realizar una tarea mediante un tipo de Windows Runtime o un tipo que proporcione .NET para aplicaciones para UWP. Le aconsejamos que no trate de combinar los tipos de .NET con los tipos de Windows Runtime. Trata de mantenerte en uno de los dos tipos. Por ejemplo, puede analizar un flujo de XML con el tipo Windows.Data.Xml.Dom.XmlDocument (un tipo de Windows Runtime) o con el tipo System.Xml.XmlReader (un tipo de .NET). Usa la API que pertenezca a la misma tecnología que el flujo. Por ejemplo, si lees xml desde MemoryStream, usa el tipo System.Xml.XmlReader porque los dos son tipos de .NET. Si lee desde un archivo, use el tipo Windows.Data.Xml.Dom.XmlDocument, ya que las API del archivo y XmlDocument están implementados en los componentes nativos de Windows Runtime.

Copiar objetos de Windows Runtime a tipos de .NET

Cuando un componente de Windows Runtime devuelve un objeto de Windows Runtime, puede resultar útil copiar el objeto devuelto en un objeto de .NET. Cuando trabajas con colecciones y flujos, esto resulta especialmente importante.

Si llamas a una API de Windows Runtime que devuelve una colección y después guardas dicha colección y tienes acceso a ella varias veces, puede resultar útil copiarla en una colección de .NET y usar la versión de .NET de ahí en adelante.

Almacene en la caché los resultados de las llamadas a los componentes de Windows Runtime para usarlos más adelante.

Es posible mejorar el rendimiento guardando valores en variables locales en lugar de obtener acceso a un tipo de Windows Runtime varias veces. Esto puede ser particularmente beneficioso si usas un valor dentro de un bucle. Evalúa tu aplicación para ver si el uso de variables locales mejora su rendimiento. Usar valores en caché puede aumentar la velocidad de la aplicación, porque dedicará menos tiempo a la interoperabilidad.

Combinación de llamadas a los componentes de Windows Runtime

Trata de completar las tareas con la menor cantidad posible de llamadas a objetos de UWP. Por ejemplo, suele ser mejor leer una gran cantidad de datos desde un flujo que leer pequeñas cantidades de una vez.

Usa las API que agrupan trabajo en la menor cantidad posible de llamadas, en lugar de usar las API que realizan menos trabajo y necesitan más llamadas. Por ejemplo, crear un objeto llamando a los constructores que inicializan varias propiedades es preferible a llamar al constructor predeterminado y asignar propiedades una a una.

Compilación de componentes de Windows Runtime

Si escribe un componente de Windows Runtime que puedan usar las aplicaciones escritas en C++ o JavaScript, asegúrese de que esté diseñado para lograr un buen rendimiento. Todas las sugerencias para lograr el buen rendimiento de las aplicaciones se aplican a los componentes. Evalúa tu componente para saber qué API tienen modelos de alta densidad de tráfico. Para esas áreas, considera proporcionar aquellas API que permitan que los usuarios realicen trabajo con pocas llamadas.

Mantener la rapidez de la aplicación al usar interoperabilidad en código administrado

Windows Runtime facilita la interoperabilidad entre el código administrado y nativo, pero si no es cuidadoso puede verse afectado el rendimiento. Aquí te mostramos cómo obtener un buen rendimiento al usar la interoperabilidad en tus aplicaciones para UWP administradas.

Windows Runtime permite a los desarrolladores escribir aplicaciones con XAML en el lenguaje que prefieran gracias a las proyecciones de las API de Windows Runtime disponibles en cada lenguaje. Al escribir aplicaciones en C# o Visual Basic, esta comodidad implica un costo de interoperabilidad, ya que las API de Windows Runtime suelen implementarse en código nativo, mientras que las invocaciones de Windows Runtime desde C# o Visual Basic requieren que CLR se transforme de un marco de pila administrado en uno nativo y calcule las referencias de los parámetros de función en las representaciones a las que puede obtener acceso el código nativo. Esta sobrecarga es mínima en la mayoría de las aplicaciones. Pero cuando se realizan muchas llamadas (cientos de miles a millones) a las API de Windows Runtime en la ruta crítica de una aplicación, este coste puede llegar a ser evidente. En general quieres garantizar que el tiempo invertido en la transición de idiomas sea escaso en relación con la ejecución del resto del código. Esto se muestra en el siguiente diagrama.

Las transiciones de interoperabilidad no deben regir el tiempo de ejecución del programa.

Los tipos enumerados en .NET para las aplicaciones de Windows no incurren en este costo de interoperabilidad cuando se usan desde C# o Visual Basic. Como regla general, puedes suponer que los tipos de espacios de nombres que empiezan con “Windows.” forman parte del conjunto de API de Windows Runtime que proporciona Windows, y los tipos los de espacios de nombres que comienzan por "System". son tipos de .NET. Tenga en cuenta que incluso el uso simple de los tipos de Windows Runtime conlleva un costo de interoperabilidad para la asignación o el acceso a la propiedad.

Debes medir tu aplicación y determinar si la interoperabilidad está consumiendo gran parte de su tiempo de ejecución antes de optimizar los costes. Cuando analiza el rendimiento de la aplicación con Visual Studio, puede obtener con facilidad un límite máximo de costos de interoperabilidad mediante la vista Funciones y consultando el tiempo transcurrido en métodos que llaman a Windows Runtime.

Si tu aplicación es lenta debido a una sobrecarga de interoperabilidad, para mejorar su rendimiento puedes reducir las llamadas a las API de Windows Runtime en las rutas de código activas. Por ejemplo, el motor de un juego que realiza una gran cantidad de cálculos de física al consultar constantemente la posición y las dimensiones de UIElements puede ahorrar mucho tiempo si almacena la información necesaria de UIElements en variables locales, realiza los cálculos en estos valores almacenados en caché y vuelve a asignar el resultado final a UIElements una vez acaba. Por poner otro ejemplo, si el código de C# o Visual Basic obtiene acceso de manera constante a una colección, es más eficaz usar una colección del espacio de nombres System.Collections que otra del espacio de nombres Windows.Foundation.Collections. También puede combinar llamadas a componentes de Windows Runtime; por ejemplo, al usar las API de Windows.Storage.BulkAccess.

Compilar componentes de UWP

Si escribe un componente de Windows Runtime para usar en aplicaciones escritas en C++ o JavaScript, asegúrese de que esté diseñado para lograr un buen rendimiento. La superficie de API define el límite de interoperabilidad y define el grado hasta el que los usuarios deberán usar la guía de este tema. Si distribuyes componentes a otras partes, entonces este tema es especialmente importante.

Todas las sugerencias para lograr el buen rendimiento de las aplicaciones se aplican a los componentes. Evalúa tu componente para saber qué API tienen modelos de alta densidad de tráfico. Para esas áreas, considera proporcionar aquellas API que permitan que los usuarios realicen trabajo con pocas llamadas. Se ha invertido mucho esfuerzo para diseñar Windows Runtime y que las aplicaciones puedan usar esta opción sin superar repetidas veces el límite de interoperabilidad.