Compartir a través de


Rendimiento de Windows Workflow Foundation 4

.NET Framework 4 incluye una revisión importante de Windows Workflow Foundation (WF) con grandes inversiones en rendimiento. Esta nueva revisión presenta cambios de diseño significativos de las versiones anteriores de WF que se incluyen como parte de .NET Framework 3.0 y .NET Framework 3.5. Se ha rediseñado del núcleo del modelo de programación, el tiempo de ejecución y las herramientas para mejorar considerablemente el rendimiento y la facilidad de uso. En este tema se muestran las características de rendimiento importantes de estas revisiones y se comparan con las de la versión anterior.

El rendimiento de los componentes de flujo de trabajo individual ha aumentado por órdenes de magnitud entre WF3 y WF4. Esto deja la brecha entre los servicios de Windows Communication Foundation (WCF) codificados a mano y los servicios de flujo de trabajo de WCF bastante pequeña. La latencia del flujo de trabajo se ha reducido significativamente en WF4. El rendimiento de persistencia ha aumentado en un factor de 2,5 a 3,0. La supervisión del estado por medio del seguimiento del flujo de trabajo tiene una sobrecarga significativamente menor. Estas son razones convincentes para migrar o adoptar WF4 en las aplicaciones.

Terminología

La versión de WF introducida en .NET Framework 4 se denominará WF4 para el resto de este tema. WF se introdujo en .NET Framework 3.0 y tenía algunas revisiones menores a través de .NET Framework 3.5 SP1. La versión de .NET Framework 3.5 de Workflow Foundation se denominará WF3 para el resto de este tema. WF3 se incluye en .NET Framework 4 en paralelo con WF4. Para obtener más información sobre cómo migrar artefactos WF3 a WF4, consulte: Guía de migración de Windows Workflow Foundation 4.

Windows Communication Foundation (WCF) es el modelo de programación unificado de Microsoft para crear aplicaciones orientadas a servicios. Se introdujo por primera vez como parte de .NET Framework 3.0 junto con WF3 y ahora es uno de los componentes clave de .NET Framework.

AppFabric de Windows Server es un conjunto de tecnologías integradas que facilitan la compilación, escalado y administración de aplicaciones web y compuestas que se ejecutan en IIS. Proporciona herramientas para supervisar y administrar servicios y flujos de trabajo. Para obtener más información, vea Windows Server AppFabric 1.0.

Objetivos

El objetivo de este tema es mostrar las características de rendimiento de WF4 con datos medidos para diferentes escenarios. También proporciona comparaciones detalladas entre WF4 y WF3 y, por tanto, muestra las grandes mejoras que se han realizado en esta nueva revisión. Los escenarios y datos presentados en este artículo cuantifican el costo subyacente de diferentes aspectos de WF4 y WF3. Estos datos son útiles para comprender las características de rendimiento de WF4 y pueden ser útiles para planear migraciones de WF3 a WF4 o usar WF4 en el desarrollo de aplicaciones. Sin embargo, se debe tener cuidado en las conclusiones extraídas de los datos presentados en este artículo. El rendimiento de una aplicación de flujo de trabajo compuesto depende en gran medida de cómo se implementa el flujo de trabajo y cómo se integran los distintos componentes. Uno debe medir cada aplicación para determinar las características de rendimiento de esa aplicación.

Introducción a las mejoras de rendimiento de WF4

WF4 se diseñó e implementó cuidadosamente con alto rendimiento y escalabilidad, que se describen en las secciones siguientes.

Tiempo de ejecución de WF

En el núcleo del entorno de ejecución de WF es un programador asincrónico que controla la ejecución de las actividades en un flujo de trabajo. Proporciona un entorno de ejecución eficaz y predecible para las actividades. El entorno tiene un contrato bien definido en materia de ejecución, continuación, realización, cancelación y control de excepciones, así como un modelo de subprocesos predecible.

En comparación con WF3, el entorno de ejecución de WF4 tiene un programador más eficaz. Utiliza el mismo grupo de subprocesos de E/S que se emplea para WCF, lo cual es muy eficiente al ejecutar tareas agrupadas. La cola del planificador de elementos de trabajo interno está optimizada para los patrones de uso más frecuentes. El tiempo de ejecución de WF4 también administra los estados de ejecución de una manera muy ligera con una lógica mínima de sincronización y control de eventos, mientras que WF3 depende del registro de eventos de gran peso e invocación para realizar una sincronización compleja para las transiciones de estado.

Almacenamiento y flujo de datos

En WF3, los datos asociados a una actividad se modelan mediante propiedades de dependencia implementadas por el tipo DependencyProperty. El patrón de propiedad de dependencia se introdujo en Windows Presentation Foundation (WPF). En general, este patrón es muy flexible para admitir enlaces de datos sencillos y otras características de la interfaz de usuario. Sin embargo, el patrón requiere que las propiedades se definan como campos estáticos en la definición de flujo de trabajo. El establecimiento o la obtención de los valores de propiedad por parte del entorno de ejecución de WF suponen una lógica de búsqueda avanzada.

WF4 usa una lógica clara de ámbito de datos para mejorar considerablemente cómo se controlan los datos en un flujo de trabajo. Separa los datos almacenados en una actividad de los datos que fluyen a través de los límites de actividad mediante dos conceptos diferentes: variables y argumentos. Con el uso de un ámbito jerárquico claro para las variables y los argumentos "In/Out/InOut", la complejidad del uso de datos para las actividades se reduce drásticamente y el período de duración de los datos también se amplía de forma automática. Las actividades tienen una signatura bien definida descrita por sus argumentos. Al inspeccionar simplemente una actividad, puede determinar qué datos espera recibir y qué datos se producirán por ella como resultado de su ejecución.

En las actividades de WF3 se inicializaron cuando se creó un flujo de trabajo. En las actividades de WF 4 solo se inicializan cuando se ejecutan las actividades correspondientes. Esto permite un ciclo de vida de actividad más sencillo sin realizar operaciones initialize/Uninitialize cuando se crea una nueva instancia de flujo de trabajo y, por tanto, ha logrado una mayor eficacia.

Flujo de control

Al igual que en cualquier lenguaje de programación, WF proporciona compatibilidad con flujos de control para las definiciones de flujo de trabajo mediante la introducción de un conjunto de actividades de flujo de control para secuenciación, bucles, bifurcaciones y otros patrones. En WF3, cuando es necesario volver a ejecutar la misma actividad, se crea un nuevo ActivityExecutionContext y la actividad se clona mediante una lógica de serialización y deserialización de peso pesado basada en BinaryFormatter. Normalmente, el rendimiento de los flujos de control iterativos es mucho más lento que ejecutar una secuencia de actividades.

WF4 controla esto de forma bastante diferente. Toma la plantilla de actividad, crea un nuevo objeto ActivityInstance y lo agrega a la cola del programador. Este proceso completo solo implica la creación explícita de objetos y es muy ligero.

Programación asincrónica

Las aplicaciones suelen tener un mejor rendimiento y escalabilidad con programación asincrónica para operaciones de bloqueo de larga duración, como operaciones de E/S o de computación distribuida. WF4 proporciona compatibilidad asincrónica a través de los tipos de actividad base AsyncCodeActivity, AsyncCodeActivity<TResult>. El runtime entiende las actividades asincrónicas de forma nativa y, por lo tanto, puede colocar automáticamente la instancia en una zona sin persistencia mientras el trabajo asincrónico está pendiente. Las actividades personalizadas pueden derivar de estos tipos para realizar tareas asincrónicas sin retener el hilo del planificador de flujo de trabajo y bloquear las actividades que puedan ejecutarse en paralelo.

Mensajería

Inicialmente WF3 tenía compatibilidad con mensajería muy limitada a través de eventos externos o invocaciones de servicios web. En .NET Framework 3.5, los flujos de trabajo se podían implementar como clientes WCF o exponerse como servicios WCF a través de SendActivity y ReceiveActivity. En WF4, el concepto de programación de mensajería basada en flujos de trabajo se ha reforzado aún más a través de la estrecha integración de la lógica de mensajería WCF en WF.

La canalización de procesamiento de mensajes unificado proporcionada en WCF en .NET 4 ayuda a los servicios WF4 a tener un rendimiento y escalabilidad considerablemente mejores que WF3. WF4 también proporciona compatibilidad con programación de mensajería más completa que puede modelar patrones complejos de intercambio de mensajes (MEP). Los desarrolladores pueden usar contratos de servicio con tipo para lograr una programación sencilla o contratos de servicio sin tipo para lograr un mejor rendimiento sin pagar los costos de serialización. La compatibilidad con el almacenamiento en caché del canal del lado cliente a través de la SendMessageChannelCache clase en WF4 ayuda a los desarrolladores a crear aplicaciones rápidas con un esfuerzo mínimo. Para obtener más información, consulte Cambio de los niveles de uso compartido de caché para actividades de envío.

Programación declarativa

WF4 proporciona un marco de programación declarativo sencillo y limpio para modelar los procesos y servicios empresariales. El modelo de programación admite la composición totalmente declarativa de las actividades, sin código adicional, lo que simplifica considerablemente la creación de flujos de trabajo. En .NET Framework 4, el marco de programación declarativo basado en XAML se ha unificado en el ensamblado único System.Xaml.dll para admitir WPF y WF.

En WF4, XAML proporciona una experiencia verdaderamente declarativa y permite definir toda la definición del flujo de trabajo en el marcado XML, haciendo referencia a actividades y tipos creados mediante .NET. Esto fue difícil de hacer en WF3 con formato XOML sin implicar lógica de código subyacente personalizada. La nueva pila XAML de .NET 4 tiene un rendimiento mucho mejor en la serialización o deserialización de artefactos de flujo de trabajo y hace que la programación declarativa sea más atractiva y sólida.

Diseñador de flujo de trabajo

La compatibilidad de programación totalmente declarativa para WF4 impone explícitamente requisitos más altos para el rendimiento del tiempo de diseño para flujos de trabajo de gran tamaño. El diseñador de flujos de trabajo de WF4 tiene una escalabilidad mucho mejor para flujos de trabajo de gran tamaño que para WF3. Con la compatibilidad con la virtualización de la interfaz de usuario, el diseñador puede cargar fácilmente un flujo de trabajo grande de 1000 actividades en unos segundos, mientras que es casi imposible cargar un flujo de trabajo de algunas cientos de actividades con el diseñador WF3.

Comparaciones de rendimiento de nivel de componente

Esta sección contiene datos sobre comparaciones directas entre actividades individuales en flujos de trabajo WF3 y WF4. Las áreas clave, como la persistencia, tienen un impacto más profundo en el rendimiento que los componentes de actividad individuales. Las mejoras de rendimiento en los componentes individuales de WF4 son importantes, ya que los componentes ahora son lo suficientemente rápidos como para compararse con la lógica de orquestación codificada a mano. Un ejemplo de lo cual se trata en la sección siguiente: "Escenario de composición de servicios".

Configuración del entorno

Configuración del entorno para la medición del rendimiento del flujo de trabajo

En la ilustración anterior se muestra la configuración de la máquina que se usa para la medición de rendimiento de nivel de componente. Un solo servidor y cinco clientes conectados a través de una interfaz de red Ethernet de 1 Gbps. Para realizar mediciones sencillas, el servidor está configurado para usar un único núcleo de un servidor de doble proc/quad-core que ejecuta Windows Server 2008 x86. La utilización de la CPU del sistema se mantiene en casi el 100%.

Detalles de la prueba

Es probable que WF3 CodeActivity sea la actividad más sencilla que se puede usar en un flujo de trabajo de WF3. La actividad llama a un método en el código subyacente en el que el programador de flujo de trabajo puede colocar código personalizado. En WF4, no hay ninguna analogía directa con wf3 CodeActivity que proporciona la misma funcionalidad. Tenga en cuenta que hay una CodeActivity clase base en WF4 que no está relacionada con WF3 CodeActivity. Se anima a los autores de flujos de trabajo a crear actividades personalizadas y desarrollar flujos de trabajo basados únicamente en XAML. En las pruebas siguientes, se usa una actividad denominada Comment en lugar de un CodeActivity vacío en flujos de trabajo de WF4. El código de la Comment actividad es el siguiente:

[ContentProperty("Body")]
    public sealed class Comment : CodeActivity
    {
        public Comment()
            : base()
        {
        }

        [DefaultValue(null)]
        public Activity Body
        {
            get;
            set;
        }

        protected override void Execute(CodeActivityContext context)
        {
        }
    }

Flujo de trabajo vacío

Esta prueba utiliza un flujo de trabajo de secuencia sin actividades secundarias.

Actividad única

El flujo de trabajo es un flujo de trabajo de secuencia que contiene una actividad secundaria. La actividad es un CodeActivity sin código en el caso de WF3 y un Comment en el caso de WF4.

While con 1000 iteraciones

El flujo de trabajo de la secuencia contiene una actividad While con una actividad secundaria en el bucle que no realiza ningún trabajo.

Replicador en comparación con ParallelForEach

ReplicatorActivity en WF3 tiene modos de ejecución secuenciales y paralelos. En modo secuencial, el rendimiento de la actividad es similar al WhileActivity. ReplicatorActivity es más útil para la ejecución en paralelo. El equivalente de WF4 es la actividad ParallelForEach<T>.

En el diagrama siguiente se muestran los flujos de trabajo usados para esta prueba. El flujo de trabajo de WF3 está a la izquierda y el flujo de trabajo de WF4 está a la derecha.

WF3 ReplicatorActivity y WF4 ParallelForEach

Flujo de trabajo secuencial con cinco actividades

Esta prueba está pensada para mostrar el efecto de tener varias actividades ejecutadas en secuencia. Hay cinco actividades en la secuencia.

Ámbito de transacción

La prueba de ámbito de transacción difiere de las otras pruebas ligeramente en que no se crea una nueva instancia de flujo de trabajo para cada iteración. En su lugar, el flujo de trabajo se estructura con un bucle while que contiene una actividad TransactionScope que a su vez incluye una única actividad que no realiza ninguna función. Cada ejecución de un lote de 50 iteraciones a través del bucle while se cuenta como una sola operación.

Compensación

El flujo de trabajo wf3 tiene una sola actividad compensable denominada WorkScope. La actividad simplemente implementa la ICompensatableActivity interfaz :

class WorkScope :
        CompositeActivity, ICompensatableActivity
    {
        public WorkScope() : base() { }

        public WorkScope(string name)
        {
            this.Name = name;
        }

        public ActivityExecutionStatus Compensate(
            ActivityExecutionContext executionContext)
        {
            return ActivityExecutionStatus.Closed;
        }
    }

El controlador de errores tiene como destino la WorkScope actividad. El flujo de trabajo wf4 es igualmente simplista. Una actividad CompensableActivity tiene un cuerpo y un controlador de compensación. Una compensación explícita es el elemento siguiente en la secuencia. La actividad del cuerpo y la actividad del controlador de compensación son implementaciones vacías:

public sealed class CompensableActivityEmptyCompensation : CodeActivity
    {
        public CompensableActivityEmptyCompensation()
            : base() { }

        public Activity Body { get; set; }

        protected override void Execute(CodeActivityContext context) { }
    }
    public sealed class CompensableActivityEmptyBody : CodeActivity
    {
        public CompensableActivityEmptyBody()
            : base() { }

        public Activity Body { get; set; }

        protected override void Execute(CodeActivityContext context) { }
    }

En el diagrama siguiente se muestra el flujo de trabajo de compensación básico. El flujo de trabajo de WF3 está a la izquierda y el flujo de trabajo de WF4 está a la derecha.

Flujos de trabajo básicos de compensación de WF3 y WF4

Resultados de pruebas de rendimiento

Tabla que muestra los datos de resultados de pruebas de rendimiento

Gráfico de columnas que compara los datos de pruebas de rendimiento de WF3 y WF4

Todas las pruebas se miden en flujos de trabajo por segundo con la excepción de la prueba de ámbito de transacción. Como se puede ver anteriormente, el rendimiento del entorno de ejecución de WF ha mejorado en todos los aspectos, especialmente en áreas que requieren múltiples ejecuciones de la misma actividad, como el bucle 'while'.

Escenario de composición del servicio

Como se muestra en la sección anterior, "Comparaciones de rendimiento de nivel de componente", se ha producido una reducción significativa de la sobrecarga entre WF3 y WF4. Los servicios de flujo de trabajo de WCF ahora pueden coincidir casi con el rendimiento de los servicios WCF codificados a mano, pero siguen teniendo todas las ventajas del entorno de ejecución de WF. En este escenario de prueba se compara un servicio WCF con un servicio de flujo de trabajo WCF en WF4.

Servicio de tienda en línea

Uno de los puntos fuertes de Windows Workflow Foundation es la capacidad de componer procesos mediante varios servicios. En este ejemplo, hay un servicio de tienda en línea que organiza dos llamadas de servicio para comprar un pedido. El primer paso es validar el pedido mediante un servicio de validación de pedidos. El segundo paso consiste en rellenar el pedido mediante un servicio de almacenamiento.

Los dos servicios back-end, Order Validating Service y Warehouse Service, siguen siendo los mismos para ambas pruebas. La parte que cambia es el servicio de tienda en línea que realiza la orquestación. En un caso, el servicio está codificado a mano como un servicio WCF. En el otro caso, el servicio se escribe como un servicio de flujo de trabajo WCF en WF4. Las características específicas de WF, como el seguimiento y la persistencia, están desactivadas para esta prueba.

Medio ambiente

Configuración del entorno para la medición del rendimiento

Las solicitudes de cliente se realizan al servicio de tienda en línea a través de HTTP desde varios equipos. Un único equipo hospeda los tres servicios. La capa de transporte entre el servicio de tienda en línea y los servicios back-end es TCP o HTTP. La medición de operaciones/segundo se basa en el número de llamadas completadas PurchaseOrder realizadas al servicio de la Tienda en línea. La agrupación de canales es una nueva característica disponible en WF4. En la parte de WCF de esta prueba, la agrupación de canales no se proporciona de manera predeterminada, por lo que se usó una implementación codificada manualmente de una técnica de agrupación simple en el servicio de tienda en línea.

Rendimiento

Gráfico de columnas que muestra el rendimiento del servicio de tienda en línea

Al conectar los servicios TCP de back-end sin agrupación de canales, el servicio WF tiene un impacto del 17,2 % en el rendimiento. Con la agrupación de canales, la reducción es de aproximadamente el 23,8%. Para HTTP, el impacto es mucho menor: 4.3% sin agrupación y 8.1% con agrupación. También es importante tener en cuenta que la agrupación de canales proporciona muy poca ventaja al usar HTTP.

Aunque hay sobrecarga del tiempo de ejecución de WF4 en comparación con un servicio WCF codificado a mano en esta prueba, podría considerarse un escenario peor. Los dos servicios back-end de esta prueba realizan muy poco trabajo. En un escenario real de un extremo a otro, estos servicios realizarían operaciones más costosas, como las llamadas de base de datos, lo que hace que el impacto en el rendimiento de la capa de transporte sea menos importante. Esto además de las ventajas de las características disponibles en WF4 hace que Workflow Foundation sea una opción viable para crear servicios de orquestación.

Consideraciones clave sobre el rendimiento

Las áreas de características de esta sección, a excepción de la interoperabilidad, han cambiado drásticamente entre WF3 y WF4. Esto afecta al diseño de aplicaciones de flujo de trabajo, así como al rendimiento.

Latencia de activación de flujo de trabajo

En una aplicación de servicio de flujo de trabajo WCF, la latencia al iniciar un nuevo flujo de trabajo o cargar un flujo de trabajo existente es importante, ya que puede ser un obstáculo. Este caso de prueba compara un host XOML de WF3 con un host XAMLX de WF4 en un escenario típico.

Configuración del entorno

Configuración del entorno para pruebas de latencia y rendimiento

Configuración de pruebas

En el escenario, un equipo cliente se comunica con un servicio de flujo de trabajo de WCF mediante la correlación basada en contexto. La correlación de contexto requiere un enlace de contexto especial y usa un encabezado de contexto o una cookie para relacionar los mensajes con la instancia de flujo de trabajo correcta. Tiene una ventaja de rendimiento en que el identificador de correlación se encuentra en el encabezado del mensaje, por lo que no es necesario analizar el cuerpo del mensaje.

El servicio creará un nuevo flujo de trabajo con la solicitud y enviará una respuesta inmediata para que la medición de la latencia no incluya el tiempo invertido en ejecutar el flujo de trabajo. El flujo de trabajo de WF3 es XOML con un código subyacente y el flujo de trabajo wf4 es completamente XAML. El flujo de trabajo wf4 tiene este aspecto:

Flujo de trabajo de ámbito de correlación de WF4

La Receive actividad crea la instancia de flujo de trabajo. Un valor pasado en el mensaje recibido se refleja en el mensaje de respuesta. Una secuencia que sigue a la respuesta contiene el resto del flujo de trabajo. En el caso anterior, solo se muestra una actividad de comentario. El número de actividades de comentario se cambia para simular la complejidad del flujo de trabajo. Una actividad de comentario es equivalente a un WF3 CodeActivity que no realiza ningún trabajo. Para obtener más información sobre la actividad de comentarios, consulte la sección "Comparación de rendimiento de nivel de componente" anteriormente en este artículo.

Resultados de pruebas

Latencia en frío y en caliente para los servicios de flujo de trabajo de WCF.

Gráfico de columnas que muestra la latencia fría y cálida para los servicios de flujo de trabajo de WCF utilizando WF3 y WF4

En el gráfico anterior, cold hace referencia al caso en el que no existe un flujo WorkflowServiceHost de trabajo determinado. En otras palabras, la latencia en frío se produce cuando el flujo de trabajo se utiliza por primera vez y el XOML o el XAML deben compilarse. La latencia cálida se refiere al tiempo necesario para crear una nueva instancia de flujo de trabajo cuando el tipo de flujo de trabajo ya se ha compilado. La complejidad del flujo de trabajo hace muy poca diferencia en el caso WF4, pero tiene una progresión lineal en el caso WF3.

Rendimiento de correlación

WF4 presenta una nueva característica de correlación basada en contenido. WF3 solo proporcionó una correlación basada en contexto. La correlación basada en contexto solo se puede realizar a través de enlaces de canal WCF específicos. El identificador de flujo de trabajo se inserta en el encabezado del mensaje al usar estos enlaces. El entorno de ejecución de WF3 solo podía identificar un flujo de trabajo por su identificador. Con la correlación basada en contenido, el autor del flujo de trabajo puede crear una clave de correlación de un fragmento de datos relevante, como un número de cuenta o un identificador de cliente.

La correlación basada en contexto tiene una ventaja de rendimiento en que la clave de correlación se encuentra en el encabezado del mensaje. La clave se puede leer desde el mensaje sin deserialización ni copia del mensaje. En la correlación basada en contenido, la clave de correlación se almacena en el cuerpo del mensaje. Se usa una expresión XPath para buscar la clave. El costo de este procesamiento adicional depende del tamaño del mensaje, la profundidad de la clave en el cuerpo y el número de claves. Esta prueba compara la correlación basada en contexto y contenido y también muestra la degradación del rendimiento al usar varias claves.

Configuración del entorno

Configuración del entorno para la prueba de rendimiento del flujo de trabajo

Configuración de pruebas

Prueba del flujo de trabajo de rendimiento de la correlación

El flujo de trabajo anterior es el mismo que se usa en la sección Persistencia . Para las pruebas de correlación sin persistencia, no hay ningún proveedor de persistencia instalado en el tiempo de ejecución. La correlación se produce en dos lugares: CreateOrder y CompleteOrder.

Resultados de pruebas

Rendimiento de Correlación

En este gráfico se muestra una disminución del rendimiento a medida que aumenta el número de claves usadas en la correlación basada en contenido. La similitud en las curvas entre TCP y HTTP indica la sobrecarga asociada a estos protocolos.

Correlación con persistencia

Con un flujo de trabajo persistente, la presión de CPU de la correlación basada en contenido cambia del tiempo de ejecución del flujo de trabajo a la base de datos SQL. Los procedimientos almacenados del proveedor de persistencia de SQL realizan el trabajo de hacer coincidir las claves para localizar el flujo de trabajo adecuado.

Gráfico de líneas que muestra los resultados de correlación y persistencia

La correlación basada en contexto sigue siendo más rápida que la correlación basada en contenido. Sin embargo, la diferencia es menos pronunciada, ya que la persistencia tiene más impacto en el rendimiento que en la correlación.

Rendimiento de flujo de trabajo complejo

La complejidad de un flujo de trabajo no se mide solo por el número de actividades. Las actividades compuestas pueden contener muchas actividades secundarias y esas actividades secundarias también pueden ser actividades compuestas. A medida que aumenta el número de niveles de anidamiento, también aumenta el número de actividades que pueden estar actualmente en estado de ejecución y el número de variables que pueden estar en estado. Esta prueba compara el rendimiento entre WF3 y WF4 al ejecutar flujos de trabajo complejos.

Configuración de pruebas

Estas pruebas se ejecutaron en un equipo intel Xeon X5355 @ 2,66GHz de 4 vías con 4 GB de RAM con Windows Server 2008 x64. El código de prueba se ejecuta en un proceso único con un subproceso por núcleo para alcanzar el 100% de utilización de la CPU.

Los flujos de trabajo generados para esta prueba tienen dos variables principales: profundidad y número de actividades en cada secuencia. Cada nivel de profundidad incluye una actividad paralela, un bucle, decisiones, asignaciones y secuencias. En el diseñador WF4 que se muestra a continuación, se muestra el gráfico de flujo de nivel superior. Cada actividad de diagrama de flujo es similar al diagrama de flujo principal. Puede resultar útil pensar en un fractal al imaginar este flujo de trabajo, donde la profundidad está limitada a los parámetros de la prueba.

El número de actividades de una prueba determinada viene determinada por la profundidad y el número de actividades por secuencia. La siguiente ecuación calcula el número de actividades de la prueba WF4:

Ecuación para calcular el número de actividades

El recuento de actividades de la prueba WF3 se puede calcular con una ecuación ligeramente diferente debido a una secuencia adicional:

Ecuación para calcular el número de actividades de WF3

Donde d es la profundidad y a es el número de actividades por secuencia. La lógica detrás de estas ecuaciones es que la primera constante, multiplicada por , es el número de secuencias y la segunda constante es el número estático de actividades en el nivel actual. Hay tres actividades secundarias de diagrama de flujo en cada diagrama de flujo. En el nivel de profundidad inferior, estos diagramas de flujo están vacíos, pero en los demás niveles son copias del diagrama de flujo principal. El número de actividades de cada definición de flujo de trabajo de variación de prueba se indica en la tabla siguiente:

Tabla que muestra el número de actividades usadas en cada prueba

El número de actividades de la definición de flujo de trabajo aumenta considerablemente con cada nivel de profundidad. Pero solo se ejecuta una ruta de acceso por punto de decisión en una instancia de flujo de trabajo determinada, por lo que solo se ejecuta un pequeño subconjunto de las actividades reales.

Diagrama de flujo del flujo de trabajo de rendimiento complejo

Se creó un flujo de trabajo equivalente para WF3. El diseñador de WF3 muestra el flujo de trabajo completo en el área de diseño en lugar de anidarlo; por consiguiente, es demasiado extenso para mostrarlo en este tema. A continuación se muestra un fragmento de código del flujo de trabajo.

Fragmento de código de diagrama de flujo del flujo de trabajo WF3

Para ejercer el anidamiento en un caso extremo, otro flujo de trabajo que forma parte de esta prueba utiliza 100 secuencias anidadas. En la secuencia más interna hay una actividad Comment o CodeActivity única.

Diagrama de flujo de una secuencia anidada

El seguimiento y la persistencia no se usan como parte de esta prueba.

Resultados de pruebas

Gráfico de columnas que muestra los resultados del rendimiento

Incluso con flujos de trabajo complejos con mucha profundidad y un gran número de actividades, los resultados de rendimiento son coherentes con otros números de rendimiento mostrados anteriormente en este artículo. El rendimiento de WF4 es órdenes de magnitud más rápido y se debe comparar en una escala logarítmica.

Memoria

La sobrecarga de memoria de Windows Workflow Foundation se mide en dos áreas clave: complejidad del flujo de trabajo y número de definiciones de flujo de trabajo. Las medidas de memoria se tomaron en una estación de trabajo de Windows 7 de 64 bits. Hay muchas maneras de obtener la medición del tamaño del conjunto de trabajo, como supervisar contadores de rendimiento, sondear Environment.WorkingSet o usar una herramienta como VMMap disponible en VMMap. Se usó una combinación de métodos para obtener y comprobar los resultados de cada prueba.

Prueba de complejidad del flujo de trabajo

La prueba de complejidad de flujo de trabajo mide la diferencia del espacio de trabajo basándose en la complejidad del flujo de trabajo. Además de los flujos de trabajo complejos usados en la sección anterior, se agregan nuevas variaciones para cubrir dos casos básicos: un único flujo de trabajo de actividad y una secuencia con 1000 actividades. Para estas pruebas, los flujos de trabajo se inicializan y se ejecutan para completarse en un único bucle serie durante un período de un minuto. Cada variación de prueba se ejecuta tres veces y los datos registrados son el promedio de esas tres ejecuciones.

Las dos nuevas pruebas básicas tienen flujos de trabajo similares a los que se muestran a continuación:

Flujo de trabajo complejo para WF3 y WF4

En el flujo de trabajo wf3 mostrado anteriormente, se usan actividades vacías CodeActivity . El flujo de trabajo de WF4 anterior utiliza actividades Comment. La Comment actividad se describió en la sección Comparaciones de rendimiento de nivel de componente anteriormente en este artículo.

Gráfico de columnas que muestra el uso complejo de memoria de flujo de trabajo para flujos de trabajo WF3 y WF4

Una de las tendencias claras que se deben observar en este gráfico es que el anidamiento tiene un impacto relativamente mínimo en el uso de memoria en WF3 y WF4. El impacto más significativo en la memoria proviene del número de actividades de un flujo de trabajo determinado. Dados los datos de las variaciones de la secuencia 1000, la secuencia 5 de profundidad compleja 5 y la secuencia 1 de profundidad compleja 7, es evidente que, a partir de la cifra de mil actividades, el aumento del uso de memoria se hace más apreciable. En el caso extremo (secuencia 1 de profundidad 7) donde hay 29.000 actividades aproximadamente, WF4 utiliza casi un 79% menos de memoria que WF3.

Prueba de varias definiciones de flujo de trabajo

La medición de la memoria por definición de flujo de trabajo se divide en dos pruebas diferentes debido a las opciones disponibles para hospedar flujos de trabajo en WF3 y WF4. Las pruebas se ejecutan de forma diferente a la prueba de complejidad del flujo de trabajo en que se instancia de un flujo de trabajo determinado y se ejecuta solo una vez por definición. Esto se debe a que la definición del flujo de trabajo y su host permanecen en memoria durante la vigencia de AppDomain. La memoria usada mediante la ejecución de una instancia de flujo de trabajo determinada debe limpiarse durante la recolección de elementos no utilizados. La guía de migración de WF4 contiene información más detallada sobre las opciones de hospedaje. Para obtener más información, consulte Wf Migration Cookbook: Workflow Hosting( Guía de migración de WF: Hospedaje de flujos de trabajo).

La creación de muchas definiciones de flujo de trabajo para una prueba de definición de flujo de trabajo se puede realizar de varias maneras. Por ejemplo, uno podría usar la generación de código para crear un conjunto de 1000 flujos de trabajo idénticos excepto en el nombre y guardar cada uno de esos flujos de trabajo en archivos independientes. Este enfoque se ha tomado para la prueba hospedada en la consola. En WF3, la WorkflowRuntime clase se usó para ejecutar las definiciones de flujo de trabajo. WF4 puede utilizar WorkflowApplication para crear una única instancia de flujo de trabajo o WorkflowInvoker para ejecutar directamente la actividad como si fuera una llamada de método. WorkflowApplication es un host de una sola instancia de flujo de trabajo y tiene una paridad de características más cercana a WorkflowRuntime para que se haya usado en esta prueba.

Al hospedar flujos de trabajo en IIS, es posible usar VirtualPathProvider para crear un nuevo WorkflowServiceHost en lugar de generar todos los archivos XAMLX o XOML. VirtualPathProvider controla la solicitud entrante y responde con un "archivo virtual" que se puede cargar desde una base de datos o, en este caso, generado sobre la marcha. Por lo tanto, no es necesario crear 1000 archivos físicos.

Las definiciones de flujo de trabajo usadas en la prueba de consola eran flujos de trabajo secuenciales sencillos con una sola actividad. Esta actividad única fue una actividad CodeActivity vacía en el caso de WF3 y una actividad Comment en el caso de WF4. El caso hospedado en IIS utilizaba flujos de trabajo que comienzan al recibir un mensaje y terminan al enviar una respuesta.

En la imagen siguiente se muestra un flujo de trabajo WF3 con ReceiveActivity y un flujo de trabajo WF4 con patrón de solicitud/respuesta:

Servicios de flujo de trabajo en WF3 y WF4

En la tabla siguiente se muestra la diferencia en el conjunto de trabajo entre una única definición de flujo de trabajo y 1001 definiciones:

Opciones de hospedaje Incremento de espacio de trabajo de WF3 Incremento de espacio de trabajo de WF4
Flujos de trabajo hospedados en aplicaciones de consola 18 MB 9 MB
Servicios de flujo de trabajo hospedados en IIS 446 MB 364 MB

El hospedaje de definiciones de flujo de trabajo en IIS consume mucha más memoria debido a WorkflowServiceHost, los artefactos detallados del servicio de WCF y la lógica de procesamiento de mensajes asociada al host.

En el caso del hospedaje de consola en WF3, los flujos de trabajo se implementaron en código en lugar de XOML. En WF4, el valor predeterminado es usar XAML. El XAML se almacena como un recurso incrustado en el ensamblado y se compila durante el tiempo de ejecución para proporcionar la implementación del flujo de trabajo. Hay alguna sobrecarga asociada a este proceso. Para realizar una comparación justa entre WF3 y WF4, se usaron flujos de trabajo codificados en lugar de XAML. A continuación se muestra un ejemplo de uno de los flujos de trabajo wf4:

public class Workflow1 : Activity
{
    protected override Func<Activity> Implementation
    {
        get
        {
            return new Func<Activity>(() =>
            {
                return new Sequence
                {
                    Activities = {
                        new Comment()
                    }
                };
            });
        }
        set
        {
            base.Implementation = value;
        }
    }
}

Hay muchos otros factores que pueden afectar al consumo de memoria. Todavía se aplica el mismo consejo para todos los programas administrados. En entornos hospedados en IIS, el WorkflowServiceHost objeto creado para una definición de flujo de trabajo permanece en memoria hasta que se recicla el grupo de aplicaciones. Esto debe tenerse en cuenta al escribir extensiones. Además, es mejor evitar variables "globales" (variables cuyo ámbito es todo el flujo de trabajo) y limitar el ámbito de las variables siempre que sea posible.

Servicios de runtime de flujo de trabajo

Persistencia

WF3 y WF4 se proporcionan con un proveedor de persistencia de SQL. El proveedor de persistencia de SQL wf3 es una implementación sencilla que serializa la instancia de flujo de trabajo y la almacena en un blob. Por este motivo, el rendimiento de este proveedor depende en gran medida del tamaño de la instancia de flujo de trabajo. En WF3, el tamaño de la instancia podría aumentar por muchas razones, como se explicó anteriormente en este documento. Muchos clientes eligen no usar el proveedor de persistencia de SQL predeterminado porque almacenar una instancia serializada en una base de datos no proporciona visibilidad sobre el estado del flujo de trabajo. Para encontrar un flujo de trabajo determinado sin conocer el identificador de flujo de trabajo, tendría que deserializar cada instancia persistente y examinar el contenido. Muchos desarrolladores prefieren escribir sus propios proveedores de persistencia para superar este obstáculo.

El proveedor de persistencia SQL WF4 ha intentado abordar algunas de estas preocupaciones. Las tablas de persistencia exponen cierta información, como los marcadores activos y las propiedades promocionales. La nueva característica de correlación basada en contenido en WF4 no funcionaría bien utilizando el enfoque de persistencia SQL de WF3, lo que ha provocado ciertos cambios en la organización de la instancia de flujo de trabajo persistente. Esto hace que el trabajo del proveedor de persistencia sea más complejo y ponga un esfuerzo adicional en la base de datos.

Configuración del entorno

Configuración del entorno para la prueba de rendimiento del flujo de trabajo

Configuración de pruebas

Incluso con un conjunto de características mejorado y un mejor control de simultaneidad, el proveedor de persistencia de SQL en WF4 es más rápido que el proveedor en WF3. Para mostrar esto, se comparan a continuación dos flujos de trabajo que realizan esencialmente las mismas operaciones en WF3 y WF4.

Flujo de trabajo de persistencia en WF3 a la izquierda y en WF4 a la derecha

Los dos flujos de trabajo se crean mediante un mensaje recibido. Después de enviar una respuesta inicial, el flujo de trabajo se conserva. En el caso de WF3, se utiliza una actividad TransactionScopeActivity vacía para iniciar la persistencia. Lo mismo se puede lograr en WF3 marcando una actividad como "conservar al cerrar". Un segundo mensaje correlacionado completa el flujo de trabajo. Los flujos de trabajo se conservan, pero no se descargan.

Resultados de pruebas

Gráfico de columnas que muestra la persistencia del rendimiento

Cuando el transporte entre el cliente y el nivel intermedio es HTTP, la persistencia en WF4 muestra una mejora de 2,6 veces. El transporte TCP aumenta ese factor a 3,0 veces. En todos los casos, el uso de CPU en el nivel intermedio es 98% o superior. La razón por la que el rendimiento de WF4 es mayor se debe al tiempo de ejecución de flujo de trabajo más rápido. El tamaño de la instancia serializada es bajo para ambos casos y no es un elemento importante que contribuye en esta situación.

Los flujos de trabajo WF3 y WF4 de esta prueba usan una actividad para indicar explícitamente cuándo debe producirse la persistencia. Esto tiene la ventaja de conservar el flujo de trabajo sin descargarlo. En WF3, también es posible persistir en el uso de la TimeToUnload característica, pero esto libera la instancia de flujo de trabajo de la memoria. Si un desarrollador que usa WF3 quiere asegurarse de que un flujo de trabajo persiste en determinados puntos, debe modificar la definición del flujo de trabajo o pagar el costo de descarga y volver a cargar la instancia de flujo de trabajo. Una nueva función en WF4 permite persistir sin necesidad de descargar: TimeToPersist. Esta característica permite que la instancia de flujo de trabajo se conserve inactiva, pero permanezca en la memoria hasta que se cumpla el umbral o se reanude la TimeToUnload ejecución.

Tenga en cuenta que el proveedor de persistencia de SQL WF4 realiza más trabajo en la capa de base de datos. La base de datos SQL puede convertirse en un cuello de botella, por lo que es importante supervisar el uso de cpu y disco allí. Asegúrese de incluir los siguientes contadores de rendimiento de la base de datos SQL al probar el rendimiento de las aplicaciones de flujo de trabajo:

  • Disco físico\Tiempo de lectura de disco en %

  • Disco físico\Tiempo de disco en %

  • PhysicalDisk\% tiempo de escritura del disco

  • PhysicalDisk\% Longitud promedio de la cola de disco

  • Disco físico\Media de longitud de cola de lectura de disco

  • Disco físico\Media de longitud de cola de escritura de disco

  • PhysicalDisk\Longitud actual de la cola del disco

  • Información de procesador\% de tiempo de procesador

  • Bloqueos temporales de SQL\Media de tiempo de espera de bloqueo temporal (ms)

  • Bloqueos temporales de SQL\Esperas de bloqueo temporal por segundo

Seguimiento

El seguimiento del flujo de trabajo se puede usar para realizar un seguimiento del progreso de un flujo de trabajo. La información que se incluye en los eventos de seguimiento viene determinada por un perfil de seguimiento. Cuanto más complejo sea el perfil de seguimiento, más caro se vuelve el seguimiento.

WF3 se incluye con un servicio de seguimiento basado en SQL. Este servicio podía funcionar en modo por lotes y en modo sin lotes. En modo no por lotes, los eventos de seguimiento se escriben directamente en la base de datos. En el modo por lotes, los eventos de seguimiento se recopilan en el mismo lote que el estado de la instancia de flujo de trabajo. El modo por lotes tiene el mejor rendimiento para la gama más amplia de diseños de flujo de trabajo. Sin embargo, el procesamiento por lotes puede tener un impacto negativo en el rendimiento si el flujo de trabajo ejecuta muchas actividades sin persistir y esas actividades son monitoreadas. Esto suele ocurrir en bucles y la mejor manera de evitar este escenario es diseñar bucles grandes para contener un punto de persistencia. La introducción de un punto de persistencia en un bucle también puede afectar negativamente al rendimiento, por lo que es importante medir los costos de cada uno y generar un equilibrio.

WF4 no se envía con un servicio de seguimiento SQL. La grabación de información de seguimiento en una base de datos SQL se puede controlar mejor desde un servidor de aplicaciones en lugar de estar integrada en .NET Framework. Por lo tanto, ahora AppFabric gestiona el seguimiento de SQL. El proveedor de seguimiento para uso inmediato en WF4 está basado en el Seguimiento de eventos para Windows (ETW).

ETW es un sistema de eventos de baja latencia y de nivel de kernel integrado en Windows. Utiliza un modelo de proveedor/consumidor que permite que solo exista sanción en el seguimiento de eventos cuando haya realmente un consumidor. Además de los eventos de kernel, como el procesador, el disco, la memoria y el uso de red, muchas aplicaciones también aprovechan ETW. Los eventos ETW son más eficaces que los contadores de rendimiento en que los eventos se pueden personalizar en la aplicación. Un evento puede contener texto como un identificador de flujo de trabajo o un mensaje informativo. Además, los eventos se clasifican con máscaras de bits para que el consumo de un determinado subconjunto de eventos tenga menos impacto en el rendimiento que capturar todos los eventos.

Entre las ventajas del enfoque de usar ETW para el seguimiento en lugar de SQL se incluyen:

  • La recopilación de eventos de seguimiento se puede separar a otro proceso. Esto proporciona mayor flexibilidad en la forma en que se registran los eventos.

  • Los eventos de seguimiento de ETW se combinan fácilmente con los eventos ETW de WCF u otros proveedores ETW, como un proveedor de SQL Server o kernel.

  • Los autores de flujos de trabajo no necesitan modificar un flujo de trabajo para trabajar mejor con una implementación de seguimiento determinada, como el modo por lotes del servicio de seguimiento de SQL WF3.

  • Un administrador puede activar o desactivar el seguimiento sin reciclar el proceso de host.

Las ventajas en cuanto a rendimiento para el seguimiento ETW plantean una desventaja. Los eventos ETW se pueden perder si el sistema está bajo una intensa presión de recursos. El procesamiento de eventos no está pensado para bloquear la ejecución normal del programa y, por lo tanto, no se garantiza que todos los eventos ETW se difundirán a sus suscriptores. Esto hace que el seguimiento ETW sea apropiado para la supervisión de estado pero no para el proceso de auditoría.

Aunque WF4 no tiene un proveedor de seguimiento de SQL, AppFabric sí. El enfoque de seguimiento de SQL de AppFabric consiste en suscribirse a eventos ETW con un servicio de Windows que agrupa por lotes los eventos y los escribe en una tabla SQL diseñada para inserciones rápidas. Un trabajo independiente extrae los datos de esta tabla y los transforma en tablas de informes que se pueden ver en el panel de AppFabric. Esto significa que un lote de eventos de seguimiento se controla independientemente del flujo de trabajo del que procede y, por tanto, no tiene que esperar un punto de persistencia antes de grabarse.

Los eventos ETW se pueden registrar con herramientas como logman o xperf. El archivo ETL compacto se puede ver con una herramienta como xperfview o convertir a un formato más legible, como XML, con tracerpt. En WF3, la única opción para obtener eventos de seguimiento sin una base de datos SQL es crear un servicio de seguimiento personalizado. Para obtener más información sobre ETW, vea Servicios wcF y seguimiento de eventos para windows y seguimiento de eventos: aplicaciones de Windows.

La habilitación del seguimiento de flujos de trabajo afectará al rendimiento en distintos grados. La prueba de referencia siguiente usa la herramienta logman para consumir los eventos de seguimiento ETW y registrarlos en un archivo ETL. El costo del seguimiento de SQL en AppFabric no está en el ámbito de este artículo. El perfil de seguimiento básico, que también se usa en AppFabric, se muestra en esta prueba comparativa. También se incluye el costo de seguir únicamente los eventos de monitoreo de salud. Estos eventos son útiles para solucionar problemas y determinar el rendimiento medio del sistema.

Configuración del entorno

Configuración del entorno para la prueba de rendimiento del flujo de trabajo

Resultados de pruebas

Gráfico de columnas que muestra los costos de seguimiento de flujos de trabajo

La supervisión de estado tiene un impacto en el rendimiento de un 3%, aproximadamente. El costo del perfil básico se sitúa en torno al 8%.

Interoperabilidad

WF4 es casi una reescritura completa de WF y, por tanto, los flujos de trabajo y las actividades de WF3 no son directamente compatibles con WF4. Muchos clientes que adoptaron Windows Workflow Foundation pronto tendrán definiciones de flujo de trabajo internos o de terceros y actividades personalizadas para WF3. Una manera de facilitar la transición a WF4 es usar la actividad de interoperabilidad, que puede ejecutar actividades wf3 desde dentro de un flujo de trabajo WF4. Se recomienda que la Interop actividad solo se use cuando sea necesario. Para obtener más información sobre la migración a WF4, consulte la Guía de migración de WF4.

Configuración del entorno

Configuración del entorno para la prueba de rendimiento del flujo de trabajo

Resultados de pruebas

En la tabla siguiente se muestran los resultados de ejecutar un flujo de trabajo que contiene cinco actividades en una secuencia en varias configuraciones.

Prueba Rendimiento (flujos de trabajo por segundo)
Secuencia de WF3 en runtime de WF3 1,576
Secuencia de WF3 en runtime de WF4 utilizando Interop 2.745
Secuencia de WF4 153,582

Hay un aumento notable del rendimiento al usar Interop en lugar de WF3 directamente. Sin embargo, en comparación con las actividades WF4, el aumento es insignificante.

Resumen

Las grandes inversiones en el rendimiento de WF4 han dado frutos en muchas áreas cruciales. El rendimiento individual de los componentes de flujo de trabajo es en algunos casos cientos de veces más rápido en WF4 en comparación con WF3 debido a un entorno de ejecución de WF más magro. Los números de latencia también son significativamente mejores. Teniendo en cuenta las ventajas adicionales de usar WF, esto significa que la penalización de rendimiento por usar WF en lugar de codificar manualmente los servicios de orquestación WCF es muy pequeña. El rendimiento de persistencia ha aumentado en un factor de 2,5 a 3,0. La supervisión del estado por medio del seguimiento del flujo de trabajo ahora tiene muy poca sobrecarga. Hay disponible un conjunto completo de guías de migración para aquellos que están considerando pasar de WF3 a WF4. Todo esto debería hacer que WF4 sea una opción atractiva para escribir aplicaciones complejas.