Condividi tramite


Prestazioni di Windows Workflow Foundation 4

.NET Framework 4 include una revisione importante di Windows Workflow Foundation (WF) con investimenti elevati in prestazioni. Questa nuova revisione introduce modifiche di progettazione significative rispetto alle versioni precedenti di WF fornite come parte di .NET Framework 3.0 e .NET Framework 3.5. È stato ri-progettato dal nucleo del modello di programmazione, del runtime e degli strumenti per migliorare notevolmente le prestazioni e l'usabilità. Questo argomento illustra le importanti caratteristiche delle prestazioni di queste revisioni e le confronta con quelle della versione precedente.

Le prestazioni dei singoli componenti del flusso di lavoro sono aumentate di ordine di grandezza tra WF3 e WF4. Ciò lascia il divario tra i servizi Windows Communication Foundation (WCF) codificati a mano e i servizi flusso di lavoro WCF risultare piuttosto piccolo. La latenza del flusso di lavoro è stata notevolmente ridotta in WF4. Le prestazioni di persistenza sono aumentate di un fattore da 2,5 a 3,0. Il monitoraggio della salute tramite il rilevamento del flusso di lavoro comporta un sovraccarico notevolmente inferiore. Questi sono motivi interessanti per eseguire la migrazione a o adottare WF4 nelle applicazioni.

Terminologia

La versione di WF introdotta in .NET Framework 4 verrà definita WF4 per il resto di questo argomento. WF è stato introdotto in .NET Framework 3.0 e ha avuto alcune revisioni secondarie tramite .NET Framework 3.5 SP1. La versione di .NET Framework 3.5 di Workflow Foundation verrà definita WF3 per il resto di questo argomento. WF3 viene fornito insieme a WF4 in .NET Framework 4. Per altre informazioni sulla migrazione di artefatti WF3 a WF4, vedere: Guida alla migrazione di Windows Workflow Foundation 4.

Windows Communication Foundation (WCF) è il modello di programmazione unificato di Microsoft per la creazione di applicazioni orientate ai servizi. È stato introdotto per la prima volta come parte di .NET Framework 3.0 insieme a WF3 ed è ora uno dei componenti chiave di .NET Framework.

Windows Server AppFabric è un set di tecnologie integrate che semplificano la compilazione, la scalabilità e la gestione di applicazioni Web e composite eseguite in IIS. Fornisce strumenti per il monitoraggio e la gestione di servizi e flussi di lavoro. Per altre informazioni, vedere Windows Server AppFabric 1.0.

Obiettivi

L'obiettivo di questo argomento è illustrare le caratteristiche delle prestazioni di WF4 con i dati misurati per diversi scenari. Fornisce inoltre confronti dettagliati tra WF4 e WF3 e mostra quindi i grandi miglioramenti apportati in questa nuova revisione. Gli scenari e i dati presentati in questo articolo quantificano il costo sottostante di diversi aspetti di WF4 e WF3. Questi dati sono utili per comprendere le caratteristiche delle prestazioni di WF4 e possono essere utili nella pianificazione delle migrazioni da WF3 a WF4 o tramite WF4 nello sviluppo di applicazioni. Tuttavia, occorre prestare attenzione alle conclusioni tratte dai dati presentati in questo articolo. Le prestazioni di un'applicazione flusso di lavoro composito dipendono in modo elevato dal modo in cui viene implementato il flusso di lavoro e dal modo in cui vengono integrati i diversi componenti. È necessario misurare ogni applicazione per determinare le caratteristiche delle prestazioni di tale applicazione.

Panoramica dei miglioramenti delle prestazioni di WF4

WF4 è stato progettato e implementato con attenzione con prestazioni elevate e scalabilità descritte nelle sezioni seguenti.

WF Runtime

Al centro del runtime di WF si trova un pianificatore asincrono che guida l'esecuzione delle attività in un flusso di lavoro. Offre un ambiente di esecuzione efficiente e prevedibile per le attività. L'ambiente ha un contratto ben definito per l'esecuzione, la continuazione, il completamento, l'annullamento, le eccezioni e un modello di threading prevedibile.

Rispetto a WF3, il runtime di WF4 ha un scheduler più efficiente. Sfrutta lo stesso pool di thread di I/O usato per WCF, che è molto efficiente durante l'esecuzione di elementi di lavoro in batch. La coda del pianificatore degli elementi di lavoro interna è ottimizzata per i modelli di utilizzo più comuni. Il runtime di WF4 gestisce anche gli stati di esecuzione in modo molto leggero con la logica di sincronizzazione e gestione degli eventi minima, mentre WF3 dipende dalla registrazione degli eventi pesanti e dalla chiamata per eseguire una sincronizzazione complessa per le transizioni di stato.

Archiviazione e flusso dei dati

In WF3 i dati associati a un'attività vengono modellati tramite le proprietà di dipendenza implementate dal tipo DependencyProperty. Il modello di proprietà di dipendenza è stato introdotto in Windows Presentation Foundation (WPF). In generale, questo modello è molto flessibile per supportare il data binding semplice e altre funzionalità dell'interfaccia utente. Tuttavia, il modello richiede che le proprietà vengano definite come campi statici nella definizione del flusso di lavoro. Ogni volta che il runtime di WF imposta o ottiene i valori delle proprietà, comporta una logica di ricerca molto ponderata.

WF4 usa una logica di definizione dell'ambito dei dati chiara per migliorare notevolmente il modo in cui i dati vengono gestiti in un flusso di lavoro. Separa i dati archiviati in un'attività dai dati che attraversano i limiti dell'attività usando due concetti diversi: variabili e argomenti. Usando un ambito gerarchico chiaro per le variabili e gli argomenti "In/Out/InOut", la complessità della gestione dei dati per le attività è notevolmente ridotta e anche l'ambito temporale dei dati è automaticamente limitato. Le attività hanno una firma ben definita descritta dai relativi argomenti. Esaminando semplicemente un'attività è possibile determinare quali dati si prevede di ricevere e quali dati verranno prodotti da esso come risultato dell'esecuzione.

Le attività di WF3 sono state inizializzate al momento della creazione di un flusso di lavoro. Nelle attività di WF 4 vengono inizializzate solo quando vengono eseguite le attività corrispondenti. Ciò consente un ciclo di vita delle attività più semplice senza eseguire operazioni Inizializza/Uninitialize quando viene creata una nuova istanza del flusso di lavoro, ottenendo così una maggiore efficienza

Flusso di controllo

Come in qualsiasi linguaggio di programmazione, WF fornisce il supporto per i flussi di controllo per le definizioni del flusso di lavoro introducendo un set di attività del flusso di controllo per sequenziazione, ciclo, diramazione e altri modelli. In WF3, quando è necessario eseguire nuovamente la stessa attività, viene creato un nuovo ActivityExecutionContext oggetto e l'attività viene clonata tramite una logica di serializzazione e deserializzazione pesante basata su BinaryFormatter. In genere le prestazioni per i flussi di controllo iterativi sono molto più lente rispetto all'esecuzione di una sequenza di attività.

WF4 gestisce questa operazione in modo molto diverso. Accetta il modello di attività, crea un nuovo oggetto ActivityInstance e lo aggiunge alla coda dello schedulatore. Questo intero processo comporta solo la creazione esplicita di oggetti ed è molto leggero.

Programmazione asincrona

Le applicazioni hanno in genere prestazioni e scalabilità migliori con programmazione asincrona per operazioni di blocco a esecuzione prolungata, ad esempio operazioni di I/O o di elaborazione distribuita. WF4 fornisce supporto asincrono tramite i tipi di attività di base, AsyncCodeActivity, AsyncCodeActivity<TResult>. Il runtime riconosce nativamente le attività asincrone e di conseguenza può inserire automaticamente l'istanza in una zona di non-persistenza mentre il lavoro asincrono è in corso. Le attività personalizzate possono derivare da questi tipi per eseguire operazioni asincrone senza bloccare il thread del pianificatore del flusso di lavoro e senza ostacolare eventuali attività che potrebbero essere eseguite in parallelo.

Messaggistica

Inizialmente WF3 aveva un supporto di messaggistica molto limitato tramite eventi esterni o chiamate ai servizi Web. In .NET Framework 3.5 i flussi di lavoro possono essere implementati come client WCF o esposti come servizi WCF tramite SendActivity e ReceiveActivity. In WF4 il concetto di programmazione della messaggistica basata sul flusso di lavoro è stato ulteriormente rafforzato grazie alla stretta integrazione della logica di messaggistica WCF in WF.

La pipeline di elaborazione unificata dei messaggi fornita in WCF in .NET 4 consente ai servizi WF4 di avere prestazioni e scalabilità notevolmente migliori rispetto a WF3. WF4 offre anche un supporto di programmazione di messaggistica più avanzato che può modellare modelli complessi di modelli di Scambio messaggi (MEP). Gli sviluppatori possono usare contratti di servizio tipizzato per ottenere contratti di servizio semplici da programmare o non tipizzato per ottenere prestazioni migliori senza pagare i costi di serializzazione. Il supporto della memorizzazione nella cache dei canali sul lato client tramite la SendMessageChannelCache classe in WF4 consente agli sviluppatori di creare applicazioni veloci con un impegno minimo. Per altre informazioni, vedere Modifica dei livelli di condivisione della cache per le attività di invio.

Programmazione dichiarativa

WF4 offre un framework di programmazione dichiarativo semplice e pulito per modellare processi e servizi aziendali. Il modello di programmazione supporta la composizione completamente dichiarativa delle attività, senza codice accanto, semplificando notevolmente la creazione del flusso di lavoro. In .NET Framework 4 il framework di programmazione dichiarativo basato su XAML è stato unificato nell'unico assembly System.Xaml.dll per supportare sia WPF che WF.

In WF4 XAML offre un'esperienza veramente dichiarativa e consente di definire l'intera definizione del flusso di lavoro nel markup XML, facendo riferimento ad attività e tipi compilati con .NET. Questa operazione era difficile da eseguire in WF3 con formato XOML senza coinvolgere la logica code-behind personalizzata. Il nuovo stack XAML in .NET 4 offre prestazioni molto migliori per la serializzazione/deserializzazione degli artefatti del flusso di lavoro e rende la programmazione dichiarativa più attraente e solida.

Progettazione flussi di lavoro

Il supporto di programmazione completamente dichiarativo per WF4 impone esplicitamente requisiti più elevati per le prestazioni in fase di progettazione per flussi di lavoro di grandi dimensioni. Progettazione flussi di lavoro in WF4 offre una scalabilità molto migliore per flussi di lavoro di grandi dimensioni rispetto a quelli per WF3. Con il supporto della virtualizzazione dell'interfaccia utente, la finestra di progettazione può caricare facilmente un flusso di lavoro di grandi dimensioni di 1000 attività in pochi secondi, mentre è quasi impossibile caricare un flusso di lavoro di poche centinaia di attività con la finestra di progettazione di WF3.

Confronti delle prestazioni a livello di componente

Questa sezione contiene dati sui confronti diretti tra singole attività nei flussi di lavoro di WF3 e WF4. Le aree chiave come la persistenza hanno un impatto più profondo sulle prestazioni rispetto ai singoli componenti dell'attività. I miglioramenti delle prestazioni nei singoli componenti in WF4 sono tuttavia importanti perché i componenti sono ora abbastanza veloci da confrontare con la logica di orchestrazione codificata a mano. Un esempio di cui è illustrato nella sezione successiva: "Scenario di composizione dei servizi".

Configurazione dell'ambiente

Configurazione dell'ambiente per la misurazione delle prestazioni del flusso di lavoro

La figura precedente mostra la configurazione del computer usata per la misurazione delle prestazioni a livello di componente. Un singolo server e cinque client connessi tramite un'interfaccia di rete Ethernet da 1 Gbps. Per misurazioni semplici, il server è configurato per l'uso di un singolo core di un server dual-proc/quad-core che esegue Windows Server 2008 x86. L'utilizzo della CPU di sistema viene mantenuto a quasi 100%.

Dettagli del test

WF3 CodeActivity è probabilmente l'attività più semplice che può essere usata in un flusso di lavoro di WF3. L'attività chiama un metodo nel code-behind in cui il programmatore del flusso di lavoro può inserire codice personalizzato. In WF4 non esiste un'analogia diretta con WF3 CodeActivity che fornisce la stessa funzionalità. Si noti che in WF4 è presente una CodeActivity classe base non correlata a WF3 CodeActivity. Gli autori del flusso di lavoro sono invitati a creare attività personalizzate e creare flussi di lavoro solo XAML. Nei test seguenti viene usata un'attività denominata Comment al posto di un vuoto CodeActivity nei flussi di lavoro di WF4. Il codice nell'attività Comment è il seguente:

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

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

        protected override void Execute(CodeActivityContext context)
        {
        }
    }

Flusso di lavoro vuoto

Questo test usa un flusso di lavoro sequenziale senza attività figlie.

Singola attività

Il flusso di lavoro è una sequenza che contiene un'attività figlia. L'attività è senza CodeActivity codice nel caso WF3 e un'attività Comment nel caso WF4.

Con 1000 iterazioni

Il flusso di lavoro della sequenza contiene un'attività While con un'attività figlia che non esegue alcuna operazione nel ciclo.

Replicator confrontato con ParallelForEach

ReplicatorActivity in WF3 ha modalità di esecuzione sequenziale e parallela. In modalità sequenziale, le prestazioni dell'attività sono simili a WhileActivity. Il ReplicatorActivity è più utile per l'esecuzione parallela. L'equivalente WF4 per questo è l'attività ParallelForEach<T>.

Il diagramma seguente illustra i flussi di lavoro usati per questo test. Il flusso di lavoro di WF3 si trova a sinistra e il flusso di lavoro di WF4 si trova a destra.

WF3 ReplicatorActivity e WF4 ParallelForEach

Flusso di lavoro sequenziale con cinque attività

Questo test è progettato per mostrare l'effetto di avere diverse attività eseguite in sequenza. Nella sequenza sono presenti cinque attività.

Ambito transazione

Il test dell'ambito della transazione differisce leggermente dagli altri test in quanto non viene creata una nuova istanza del flusso di lavoro per ogni iterazione. Il flusso di lavoro è invece strutturato con un ciclo while contenente un'attività TransactionScope che non svolge alcun lavoro. Ogni esecuzione di un batch di 50 iterazioni attraverso il ciclo while viene conteggiata come singola operazione.

Retribuzione

Il flusso di lavoro di WF3 ha una singola attività compensabile denominata WorkScope. L'attività implementa semplicemente l'interfaccia ICompensatableActivity :

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

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

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

Il gestore degli errori gestisce l'attività WorkScope . Il flusso di lavoro di WF4 è altrettanto semplicistico. Un CompensableActivity ha un corpo e un gestore della compensazione. Una compensazione esplicita è successiva nella sequenza. Le attività del corpo e del gestore di compensazione sono entrambe implementazioni vuote.

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

Il diagramma seguente illustra il flusso di lavoro di compensazione di base. Il flusso di lavoro di WF3 si trova a sinistra e il flusso di lavoro di WF4 si trova a destra.

Flussi di lavoro di compensazione di base di WF3 e WF4

Risultati dei test delle prestazioni

Tabella che mostra i dati dei risultati dei test delle prestazioni

Istogramma che confronta i dati di test delle prestazioni di WF3 e WF4

Tutti i test vengono misurati in flussi di lavoro al secondo, ad eccezione del test dell'ambito della transazione. Come si vede sopra, le prestazioni del runtime di WF sono migliorate in tutte le aree, soprattutto nelle aree che richiedono più esecuzioni della stessa attività come il ciclo while loop.

Scenario di composizione dei servizi

Come illustrato nella sezione precedente, "Confronti delle prestazioni a livello di componente", si è verificata una riduzione significativa del sovraccarico tra WF3 e WF4. I servizi flusso di lavoro WCF possono ora corrispondere quasi alle prestazioni dei servizi WCF codificati a mano, ma hanno comunque tutti i vantaggi del runtime di WF. Questo scenario di test confronta un servizio WCF con un servizio flusso di lavoro WCF in WF4.

Servizio store online

Uno dei punti di forza di Windows Workflow Foundation è la possibilità di comporre processi usando diversi servizi. Per questo esempio, esiste un servizio di negozio online che orchestra due chiamate di servizio per acquistare un ordine. Il primo passaggio consiste nel convalidare l'ordine usando un servizio di convalida degli ordini. Il secondo passaggio consiste nel compilare l'ordine usando un servizio warehouse.

I due servizi back-end, Order Validating Service e Warehouse Service, rimangono invariati per entrambi i test. La parte modificata è il servizio del negozio online che esegue l'orchestrazione. In un caso, il servizio viene codificato a mano come servizio WCF. Per l'altro caso, il servizio viene scritto come servizio di flusso di lavoro WCF in WF4. Le funzionalità specifiche di WF, ad esempio il rilevamento e la persistenza, vengono disattivate per questo test.

Ambiente

Configurazione dell'ambiente per la misurazione delle prestazioni

Le richieste client vengono inviate al servizio store online tramite HTTP da più computer. Un singolo computer ospita tutti e tre i servizi. Il livello di trasporto tra il servizio di archiviazione online e i servizi back-end è TCP o HTTP. La misurazione delle operazioni al secondo si basa sul numero di chiamate completate PurchaseOrder effettuate al servizio dell'Online Store. Il pooling di canali è una nuova funzionalità disponibile in WF4. Nella sezione WCF di questo test, il pool di canali non è fornito per impostazione predefinita, quindi è stata utilizzata un'implementazione manuale di una semplice tecnica di pooling nel servizio Online Store.

Prestazioni

Istogramma che mostra le prestazioni del servizio store online

La connessione ai servizi TCP back-end senza l'utilizzo del pooling dei canali ha un impatto% di 17.2 sulla velocità effettiva del servizio WF. Con il pool di canali, la penalità è di circa 23,8%. Per HTTP, l'impatto è molto inferiore: 4.3% senza pooling e 8.1% con pooling. È anche importante notare che il pool di canali offre pochissimo vantaggio quando si usa HTTP.

Anche se il runtime di WF4 presenta un sovraccarico rispetto a un servizio WCF codificato a mano in questo test, può essere considerato uno scenario peggiore. I due servizi back-end in questo test eseguono molto poco lavoro. In uno scenario end-to-end reale, questi servizi eseguono operazioni più costose come le chiamate di database, rendendo meno importante l'impatto sulle prestazioni del livello di trasporto. Questo e i vantaggi delle funzionalità disponibili in WF4 rendono Workflow Foundation una scelta valida per la creazione di servizi di orchestrazione.

Considerazioni chiave sulle prestazioni

Le aree di funzionalità di questa sezione, ad eccezione dell'interoperabilità, sono state notevolmente modificate tra WF3 e WF4. Ciò influisce sulla progettazione delle applicazioni del flusso di lavoro e sulle prestazioni.

Latenza nell'attivazione del flusso di lavoro

In un'applicazione del servizio flusso di lavoro WCF la latenza per l'avvio di un nuovo flusso di lavoro o il caricamento di un flusso di lavoro esistente è importante perché può bloccarsi. Questo test case misura un host XOML di WF3 su un host XAMLX WF4 in uno scenario tipico.

Configurazione dell'ambiente

Configurazione dell'ambiente per test di latenza e velocità effettiva

Configurazione test

Nello scenario, un computer client contatta il servizio WCF di flusso di lavoro utilizzando la correlazione basata sul contesto. La correlazione del contesto richiede un'associazione di contesto speciale e usa un'intestazione di contesto o un cookie per correlare i messaggi all'istanza del flusso di lavoro corretta. Offre un vantaggio per le prestazioni in quanto l'ID correlazione si trova nell'intestazione del messaggio in modo che il corpo del messaggio non debba essere analizzato.

Il servizio creerà un nuovo flusso di lavoro con la richiesta e invierà una risposta immediata in modo che la misurazione della latenza non includa il tempo impiegato per l'esecuzione del flusso di lavoro. Il flusso di lavoro di WF3 è XOML con code-behind e il flusso di lavoro di WF4 è interamente XAML. Il flusso di lavoro di WF4 è simile al seguente:

Workflow Ambito di Correlazione WF4

L'attività Receive crea l'istanza del flusso di lavoro. Un valore passato nel messaggio ricevuto viene restituito nel messaggio di risposta. Una sequenza che segue la risposta contiene il resto del flusso di lavoro. Nel caso precedente viene visualizzata una sola attività di commento. Il numero di attività di commento viene modificato per simulare la complessità del flusso di lavoro. Un'attività di commento equivale a un WF3 CodeActivity che non esegue alcuna operazione. Per altre informazioni sull'attività di commento, vedere la sezione "Confronto delle prestazioni a livello di componente" più indietro in questo articolo.

Risultati dei test

Latenza a freddo e a caldo per i servizi WCF di flusso di lavoro:

Istogramma che mostra la latenza fredda e calda per i servizi flusso di lavoro WCF che usano WF3 e WF4

Nel grafico precedente, cold fa riferimento al caso in cui non esiste un oggetto esistente WorkflowServiceHost per il flusso di lavoro specificato. In altre parole, la latenza a freddo si verifica quando il flusso di lavoro viene usato per la prima volta e XOML o XAML deve essere compilato. La latenza a caldo è il tempo necessario per creare una nuova istanza del flusso di lavoro quando il tipo di flusso di lavoro è già stato preparato. La complessità del flusso di lavoro fa molto poca differenza nel caso WF4, ma presenta una progressione lineare nel caso WF3.

Velocità di correlazione

WF4 introduce una nuova funzionalità di correlazione basata sul contenuto. WF3 ha fornito solo la correlazione basata sul contesto. La correlazione basata sul contesto può essere eseguita solo su associazioni di canale WCF specifiche. L'ID del flusso di lavoro viene inserito nell'intestazione del messaggio quando si usano queste associazioni. Il runtime di WF3 può identificare un flusso di lavoro solo in base al relativo ID. Con la correlazione basata sul contenuto, l'autore del flusso di lavoro può creare una chiave di correlazione da una parte di dati pertinente, ad esempio un numero di account o un ID cliente.

La correlazione basata sul contesto presenta un vantaggio in termini di prestazioni in quanto la chiave di correlazione si trova nell'intestazione del messaggio. La chiave può essere letta dal messaggio senza de-serializzazione/copia dei messaggi. Nella correlazione basata sul contenuto, la chiave di correlazione viene archiviata nel corpo del messaggio. Per individuare la chiave viene usata un'espressione XPath. Il costo di questa elaborazione aggiuntiva dipende dalle dimensioni del messaggio, dalla profondità della chiave nel corpo e dal numero di chiavi. Questo test confronta la correlazione basata sul contesto e sul contenuto e mostra anche la riduzione delle prestazioni quando si usano più chiavi.

Configurazione dell'ambiente

Configurazione dell'ambiente per il test delle prestazioni del flusso di lavoro

Configurazione test

Test del flusso di lavoro della velocità effettiva di correlazione

Il flusso di lavoro precedente è lo stesso usato nella sezione Persistenza . Per i test di correlazione senza persistenza, non è installato alcun provider di persistenza nel runtime. La correlazione si verifica in due posizioni: CreateOrder e CompleteOrder.

Risultati dei test

Grafico della velocità effettiva di correlazione

Questo grafico mostra una diminuzione delle prestazioni man mano che aumenta il numero di chiavi usate nella correlazione basata sul contenuto. La somiglianza nelle curve tra TCP e HTTP indica il sovraccarico associato a questi protocolli.

Correlazione con persistenza

Con un flusso di lavoro persistente, la pressione della CPU dalla correlazione basata sul contenuto passa dal runtime del flusso di lavoro al database SQL. Le stored procedures nel provider di persistenza SQL eseguono il lavoro di abbinare le chiavi per individuare il flusso di lavoro corretto.

Grafico a linee che mostra i risultati di correlazione e persistenza

La correlazione basata sul contesto è ancora più veloce rispetto alla correlazione basata sul contenuto. Tuttavia, la differenza è meno pronunciata perché la persistenza ha un impatto maggiore sulle prestazioni rispetto alla correlazione.

Velocità effettiva del flusso di lavoro complessa

La complessità di un flusso di lavoro non viene misurata solo in base al numero di attività. Le attività composite possono contenere molti componenti figli e questi componenti figli possono anche essere attività composite. Man mano che aumenta il numero di livelli di annidamento, aumenta anche il numero di attività attualmente in esecuzione e il numero di variabili che possono trovarsi in uno stato. Questo test confronta la velocità effettiva tra WF3 e WF4 durante l'esecuzione di flussi di lavoro complessi.

Configurazione test

Questi test sono stati eseguiti in un computer Intel Xeon X5355 a 2,66 GHz a 4 vie con 4 GB di RAM che eseguono Windows Server 2008 x64. Il codice di test viene eseguito in un singolo processo con un thread per core per raggiungere un utilizzo della CPU del 100% nel livello%.

I flussi di lavoro generati per questo test hanno due variabili principali: profondità e numero di attività in ogni sequenza. Ogni livello di profondità include un'attività parallela, ciclo while, decisioni, assegnazioni e sequenze. Nella finestra di progettazione di WF4 mostrata di seguito, è rappresentato il diagramma di flusso di livello superiore. Ogni attività del diagramma di flusso è simile al diagramma di flusso principale. Può essere utile pensare a un frattale durante la rappresentazione di questo flusso di lavoro, in cui la profondità è limitata ai parametri del test.

Il numero di attività in un determinato test è determinato dalla profondità e dal numero di attività per sequenza. L'equazione seguente calcola il numero di attività nel test di WF4:

Equazione per calcolare il numero di attività

Il conteggio delle attività del test di WF3 può essere calcolato con un'equazione leggermente diversa a causa di una sequenza aggiuntiva:

Equazione per calcolare il numero di attività di WF3

Dove d è la profondità e un è il numero di attività per sequenza. La logica alla base di queste equazioni è che la prima costante, moltiplicata per a, è il numero di sequenze e la seconda costante è il numero statico di attività nel livello corrente. In ogni diagramma di flusso sono presenti tre attività figlio di diagramma di flusso. A livello di profondità inferiore, questi diagrammi di flusso sono vuoti, ma ad altri livelli sono copie del diagramma di flusso principale. Il numero di attività nella definizione del flusso di lavoro di ogni variante di test è indicato nella tabella seguente:

Tabella che mostra il numero di attività usate in ogni test

Il numero di attività nella definizione del flusso di lavoro aumenta notevolmente con ogni livello di profondità. Tuttavia, in una determinata istanza del flusso di lavoro viene eseguito un solo percorso per punto decisionale, quindi vengono eseguiti solo un piccolo subset delle attività effettive.

Diagramma di flusso del flusso di lavoro del throughput complesso

È stato creato un flusso di lavoro equivalente per WF3. La finestra di progettazione di WF3 mostra l'intero workflow nell'area di progettazione, poiché non lo annida, pertanto è troppo grande da visualizzare in questo argomento. Di seguito è riportato un frammento di flusso di lavoro.

Frammento di diagramma di flusso del flusso di lavoro di WF3

Per sperimentare l'annidamento in un caso estremo, un altro flusso di lavoro che fa parte di questo test utilizza 100 sequenze annidate. Nella sequenza più interna vi è un singolo Comment o CodeActivity.

Diagramma di flusso di una sequenza nidificata

Il rilevamento e la persistenza non vengono usati come parte di questo test.

Risultati dei test

Istogramma che mostra i risultati delle prestazioni del throughput

Anche con flussi di lavoro complessi con molta profondità e un numero elevato di attività, i risultati delle prestazioni sono coerenti con altri numeri di velocità effettiva illustrati in precedenza in questo articolo. La velocità effettiva di WF4 è un ordine di grandezza più veloce e deve essere confrontata su una scala logaritmica.

Memoria

Il sovraccarico di memoria di Windows Workflow Foundation viene misurato in due aree chiave: complessità del flusso di lavoro e numero di definizioni del flusso di lavoro. Le misurazioni della memoria sono state eseguite su una workstation a 64 bit di Windows 7. Esistono molti modi per ottenere la misurazione delle dimensioni del working set, ad esempio il monitoraggio dei contatori delle prestazioni, il polling di Environment.WorkingSet o l'uso di uno strumento come VMMap disponibile da VMMap. È stata usata una combinazione di metodi per ottenere e verificare i risultati di ogni test.

Test di complessità del flusso di lavoro

Il test di complessità del flusso di lavoro misura la differenza del working set in base alla complessità del flusso di lavoro. Oltre ai flussi di lavoro complessi usati nella sezione precedente, vengono aggiunte nuove varianti per coprire due casi di base: un singolo flusso di lavoro di attività e una sequenza con 1000 attività. Per questi test, i flussi di lavoro vengono inizializzati ed eseguiti fino al completamento in un singolo ciclo seriale per un periodo di un minuto. Ogni variante di test viene eseguita tre volte e i dati registrati sono la media di queste tre esecuzioni.

I due nuovi test di base hanno flussi di lavoro simili a quelli illustrati di seguito:

Flusso di lavoro complesso per WF3 e WF4

Nel flusso di lavoro WF3 illustrato in precedenza vengono usate attività vuote CodeActivity . Il flusso di lavoro WF4 precedente usa le Comment attività. L'attività Comment è stata descritta nella sezione Confronto prestazioni a livello di componente più indietro in questo articolo.

Istogramma che mostra l'utilizzo complesso della memoria del flusso di lavoro per i flussi di lavoro WF3 e WF4

Una delle tendenze chiare da notare in questo grafico è che l'annidamento ha un impatto relativamente minimo sull'utilizzo della memoria sia in WF3 che in WF4. L'impatto più significativo sulla memoria deriva dal numero di attività in un determinato flusso di lavoro. Dato che i dati della sequenza 1000, la profondità complessa 5 sequenza 5 e le variazioni della profondità complessa 7 sequenza 1, è chiaro che quando il numero di attività entra nelle migliaia, l'aumento dell'utilizzo della memoria diventa più evidente. Nel caso estremo (profondità 7 sequenza 1) in cui sono presenti circa 29.000 attività, WF4 usa quasi 79% di memoria in meno rispetto a WF3.

Test di più definizioni del flusso di lavoro

La misurazione della memoria per definizione del flusso di lavoro è suddivisa in due test diversi a causa delle opzioni disponibili per l'hosting dei flussi di lavoro in WF3 e WF4. I test vengono eseguiti in modo diverso rispetto al test di complessità del flusso di lavoro in quanto un determinato flusso di lavoro viene istanzato ed eseguito una sola volta per definizione. Ciò è dovuto al fatto che la definizione del flusso di lavoro e il relativo host rimangono in memoria per la durata dell'AppDomain. La memoria usata dall'esecuzione di una determinata istanza del flusso di lavoro deve essere pulita durante l'operazione di Garbage Collection. Le indicazioni sulla migrazione per WF4 contengono informazioni più dettagliate sulle opzioni di hosting. Per altre informazioni, vedere WF Migration Cookbook: Workflow Hosting.For more information, see WF Migration Cookbook: Workflow Hosting.

La creazione di molte definizioni del flusso di lavoro per un test di definizione del flusso di lavoro può essere eseguita in diversi modi. Ad esempio, è possibile usare la generazione di codice per creare un set di 1000 flussi di lavoro identici, ad eccezione del nome e salvare ognuno di questi flussi di lavoro in file separati. Questo approccio è stato adottato per il test ospitato nella console. In WF3 la WorkflowRuntime classe è stata usata per eseguire le definizioni del flusso di lavoro. WF4 può usare WorkflowApplication per creare una singola istanza del flusso di lavoro o usare direttamente WorkflowInvoker per eseguire l'attività come se fosse un metodo. WorkflowApplication è un host di una singola istanza del flusso di lavoro e ha una parità di funzionalità più vicina a WorkflowRuntime in modo che sia stata usata in questo test.

Quando si ospitano flussi di lavoro in IIS, è possibile usare un VirtualPathProvider oggetto per creare un nuovo WorkflowServiceHost anziché generare tutti i file XAMLX o XOML. VirtualPathProvider Gestisce la richiesta in ingresso e risponde con un "file virtuale" che può essere caricato da un database o, in questo caso, generato in tempo reale. Non è quindi necessario creare 1000 file fisici.

Le definizioni del flusso di lavoro usate nel test della console erano semplici flussi di lavoro sequenziali con una singola attività. La singola attività era vuota CodeActivity per il caso WF3 e un'attività Comment per il caso WF4. Il caso ospitato da IIS usa flussi di lavoro che iniziano a ricevere un messaggio e terminano all'invio di una risposta:

L'immagine seguente mostra un flusso di lavoro WF3 con ReceiveActivity e un flusso di lavoro WF4 con modello di richiesta/risposta:

Servizi flusso di lavoro in WF3 e WF4

La tabella seguente illustra il delta del working set tra una singola definizione del flusso di lavoro e le definizioni 1001:

Opzioni di hosting WF3 Working Set Delta WF4 Set di Lavoro Delta
Flussi di lavoro ospitati nell'applicazione console 18 MB 9 MB
Servizi di flusso di lavoro ospitati da IIS 446 MB 364 MB

L'hosting delle definizioni del flusso di lavoro in IIS utilizza molta più memoria a causa di WorkflowServiceHost, degli artefatti dettagliati del servizio WCF e della logica di elaborazione dei messaggi associata all'host.

Per l'hosting della console in WF3, i flussi di lavoro sono stati implementati nel codice anziché XOML. In WF4 l'impostazione predefinita consiste nell'usare XAML. Il codice XAML viene archiviato come risorsa incorporata nell'assembly e compilato durante il runtime per fornire l'implementazione del flusso di lavoro. A questo processo è associato un sovraccarico. Per eseguire un confronto equo tra WF3 e WF4, sono stati usati flussi di lavoro codificati anziché XAML. Di seguito è riportato un esempio di uno dei flussi di lavoro di 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;
        }
    }
}

Esistono molti altri fattori che possono influire sul consumo di memoria. Lo stesso consiglio per tutti i programmi gestiti si applica ancora. Negli ambienti ospitati in IIS, l'oggetto WorkflowServiceHost creato per una definizione del flusso di lavoro rimane in memoria fino a quando il pool di applicazioni non viene riciclato. Questo aspetto deve essere tenuto presente quando si scrivono estensioni. Inoltre, è consigliabile evitare variabili "globali" (variabili con ambito per l'intero flusso di lavoro) e limitare l'ambito delle variabili laddove possibile.

Servizi di esecuzione del flusso di lavoro

Persistenza

WF3 e WF4 vengono entrambi forniti con un provider di persistenza SQL. Il provider di persistenza SQL di WF3 è una semplice implementazione che serializza l'istanza del flusso di lavoro e la archivia in un BLOB. Per questo motivo, le prestazioni di questo provider dipendono principalmente dalle dimensioni dell'istanza del flusso di lavoro. In WF3 le dimensioni dell'istanza potrebbero aumentare per molti motivi, come illustrato in precedenza in questo documento. Molti clienti scelgono di non usare il provider di persistenza SQL predefinito perché l'archiviazione di un'istanza serializzata in un database non offre visibilità sullo stato del flusso di lavoro. Per trovare un determinato flusso di lavoro senza conoscere l'ID del flusso di lavoro, è necessario deserializzare ogni istanza persistente ed esaminare il contenuto. Molti sviluppatori preferiscono scrivere i propri provider di persistenza per superare questo ostacolo.

Il provider di persistenza SQL di WF4 ha cercato di risolvere alcuni di questi problemi. Le tabelle di persistenza espongono determinate informazioni, ad esempio i segnalibri attivi e le proprietà promozionali. La nuova funzionalità di correlazione basata sul contenuto in WF4 non funziona correttamente usando l'approccio di persistenza SQL di WF3, che ha determinato alcune modifiche nell'organizzazione dell'istanza del flusso di lavoro persistente. Questo rende il processo del provider di persistenza più complesso e pone ulteriore stress sul database.

Configurazione dell'ambiente

Configurazione dell'ambiente per il test delle prestazioni del flusso di lavoro

Configurazione test

Anche con un set di funzionalità migliorato e una migliore gestione della concorrenza, il provider di persistenza SQL in WF4 è più veloce del provider in WF3. Per illustrare questo problema, vengono confrontati due flussi di lavoro che eseguono essenzialmente le stesse operazioni in WF3 e WF4.

Flusso di lavoro di persistenza in WF3 a sinistra e WF4 a destra

I due flussi di lavoro vengono entrambi creati da un messaggio ricevuto. Dopo l'invio di una risposta iniziale, lo stato del flusso di lavoro viene mantenuto. Nel caso di WF3, viene usato un elemento vuoto TransactionScopeActivity per avviare la persistenza. Lo stesso risultato potrebbe essere ottenuto in WF3 contrassegnando un'attività come "persiste alla chiusura". Un secondo messaggio correlato completa il workflow. I flussi di lavoro sono mantenuti ma non rimossi dalla memoria.

Risultati dei test

Istogramma che mostra la persistenza della velocità effettiva

Quando il trasporto tra client e livello intermedio è HTTP, la persistenza in WF4 mostra un miglioramento di 2,6 volte. Il trasporto TCP aumenta tale fattore a 3,0 volte. In tutti i casi, l'utilizzo della CPU nel livello intermedio è 98% o superiore. Il motivo per cui la portata di WF4 è maggiore è dovuto alla maggiore velocità di esecuzione del flusso di lavoro. La dimensione dell'istanza serializzata è bassa per entrambi i casi e non è un elemento principale che contribuisce in questa situazione.

Sia i flussi di lavoro WF3 che WF4 in questo test usano un'attività per indicare in modo esplicito quando deve verificarsi la persistenza. Questo ha il vantaggio di rendere persistente il flusso di lavoro senza scaricarlo. In WF3 è anche possibile mantenere l'istanza del flusso di lavoro utilizzando la funzionalità TimeToUnload, ma questo la scarica dalla memoria. Se uno sviluppatore che usa WF3 vuole assicurarsi che un flusso di lavoro venga mantenuto in determinati punti, è necessario modificare la definizione del flusso di lavoro o pagare il costo per lo scaricamento e il ricaricamento dell'istanza del flusso di lavoro. Una nuova funzionalità di WF4 consente di mantenere lo stato senza scaricare: TimeToPersist. Questa funzionalità consente di rendere persistente l'istanza inattiva del flusso di lavoro, rimanendo in memoria fino a quando la soglia TimeToUnload non viene raggiunta o l'esecuzione viene ripresa.

Si noti che il provider di persistenza SQL di WF4 esegue più operazioni nel livello di database. Il database SQL può diventare un collo di bottiglia, quindi è importante monitorare l'utilizzo della CPU e del disco. Assicurarsi di includere i contatori delle prestazioni seguenti dal database SQL durante il test delle prestazioni delle applicazioni del flusso di lavoro:

  • PhysicalDisk\%Disk Tempo di lettura

  • PhysicalDisk\ Tempo di Disco%

  • PhysicalDisk\ tempo di scrittura su disco%

  • PhysicalDisk\% lunghezza media della coda del disco

  • PhysicalDisk\Lunghezza media della coda lettura disco

  • PhysicalDisk\Lunghezza media della coda di scrittura su disco

  • PhysicalDisk\Lunghezza coda disco attuale

  • Informazioni sul processore\ tempo del processore%

  • SQLServer:Latches\Tempo medio di attesa del latch (ms)

  • SQLServer:Latch\Latch Waits/sec

Tracciamento

Il rilevamento del flusso di lavoro può essere usato per tenere traccia dello stato di avanzamento di un flusso di lavoro. Le informazioni incluse negli eventi di rilevamento sono determinate da un profilo di rilevamento. Più complesso è il profilo di rilevamento, più costoso diventa il rilevamento.

WF3 fornito con un servizio di rilevamento basato su SQL. Questo servizio può funzionare in modalità batch e non-batch. In modalità non in batch, gli eventi di rilevamento vengono scritti direttamente nel database. In modalità batch, gli eventi di rilevamento vengono raccolti nello stesso batch dello stato dell'istanza del flusso di lavoro. La modalità batch offre prestazioni ottimali per la gamma più ampia di progettazioni del flusso di lavoro. Tuttavia, l'invio in batch può avere un impatto negativo sulle prestazioni se il flusso di lavoro esegue molte attività senza rendere persistenti e tali attività vengono rilevate. Ciò si verifica in genere in cicli e il modo migliore per evitare questo scenario consiste nel progettare cicli di grandi dimensioni in modo da contenere un punto di persistenza. L'introduzione di un punto di persistenza in un ciclo può influire negativamente sulle prestazioni, quindi è importante misurare i costi di ogni ciclo e ottenere un saldo.

WF4 non viene fornito con un servizio di rilevamento SQL. La registrazione delle informazioni di rilevamento in un database SQL può essere gestita meglio da un server applicazioni anziché integrata in .NET Framework. Di conseguenza, il rilevamento SQL viene ora gestito da AppFabric. Il provider di rilevamento predefinito in WF4 si basa su Event Tracing for Windows (ETW).

ETW è un sistema di eventi a bassa latenza a livello di kernel integrato in Windows. Usa un modello provider/consumer che permette di incorrere nella penalità della tracciatura degli eventi solo quando è effettivamente presente un consumer. Oltre agli eventi del kernel, ad esempio processore, disco, memoria e utilizzo della rete, molte applicazioni sfruttano anche ETW. Gli eventi ETW sono più potenti rispetto ai contatori delle prestazioni in quanto gli eventi possono essere personalizzati per l'applicazione. Un evento può contenere testo, ad esempio un ID flusso di lavoro o un messaggio informativo. Inoltre, gli eventi vengono classificati con maschera di bit in modo che l'utilizzo di un determinato subset di eventi avrà un impatto inferiore sulle prestazioni rispetto all'acquisizione di tutti gli eventi.

I vantaggi dell'approccio all'uso di ETW per il rilevamento invece di SQL includono:

  • La raccolta di eventi di rilevamento può essere separata da un altro processo. Ciò offre maggiore flessibilità nel modo in cui vengono registrati gli eventi.

  • Gli eventi di tracciamento ETW sono facilmente combinati con gli eventi ETW di WCF o con altri provider ETW, come un provider di SQL Server o del kernel.

  • Gli autori del flusso di lavoro non devono modificare un flusso di lavoro per funzionare meglio con una particolare implementazione di rilevamento, ad esempio la modalità batch del servizio di rilevamento SQL di WF3.

  • Un amministratore può attivare o disattivare il rilevamento senza riciclare il processo host.

I vantaggi delle prestazioni del rilevamento ETW presentano uno svantaggio. Gli eventi ETW possono essere persi se il sistema è sottoposto a un'intensa pressione sulle risorse. L'elaborazione degli eventi non è destinata a bloccare l'esecuzione normale del programma e pertanto non è garantito che tutti gli eventi ETW verranno trasmessi ai propri sottoscrittori. In questo modo, il tracciamento ETW è ideale per il monitoraggio dello stato di salute, ma non adatto per la verifica.

Anche se WF4 non dispone di un provider di rilevamento SQL, AppFabric lo fa. L'approccio di rilevamento SQL di AppFabric consiste nel sottoscrivere eventi ETW con un servizio Windows che li inserisce in batch e li scrive in una tabella SQL progettata per inserimenti rapidi. Un processo separato svuota i dati da questa tabella e lo riforma nelle tabelle di report che possono essere visualizzate nel dashboard di AppFabric. Ciò significa che un batch di eventi di rilevamento viene gestito indipendentemente dal flusso di lavoro da cui proviene e pertanto non deve attendere un punto di persistenza prima di essere registrato.

Gli eventi ETW possono essere registrati con strumenti come logman o xperf. Il file ETL compatto può essere visualizzato con uno strumento come xperfview o convertito in un formato più leggibile, ad esempio XML, con tracerpt. In WF3 l'unica opzione per il rilevamento degli eventi senza un database SQL consiste nel creare un servizio di rilevamento personalizzato. Per altre informazioni su ETW, vedere Servizi WCF e Traccia eventi per applicazioni Windows ed Event Tracing - Windows.

L'abilitazione del rilevamento del flusso di lavoro influirà sulle prestazioni in diversi gradi. Il benchmark seguente usa lo strumento logman per utilizzare gli eventi di rilevamento ETW e registrarli in un file ETL. Il costo del rilevamento SQL in AppFabric non rientra nell'ambito di questo articolo. Il profilo di rilevamento di base, usato anche in AppFabric, è illustrato in questo benchmark. È incluso anche il costo di tenere traccia solo degli eventi di monitoraggio della salute. Questi eventi sono utili per la risoluzione dei problemi e per determinare la velocità effettiva media del sistema.

Configurazione dell'ambiente

Configurazione dell'ambiente per il test delle prestazioni del flusso di lavoro

Risultati dei test

Istogramma che mostra i costi di rilevamento del flusso di lavoro

Il monitoraggio della salute ha un impatto di circa 3% sulla velocità effettiva. Il costo del profilo di base è di circa 8%.

Interoperabilità

WF4 è quasi una riscrittura completa di WF e pertanto i flussi di lavoro e le attività di WF3 non sono direttamente compatibili con WF4. Molti clienti che hanno adottato Windows Workflow Foundation in anticipo avranno definizioni di flusso di lavoro interne o di terze parti e attività personalizzate per WF3. Un modo per semplificare la transizione a WF4 consiste nell'usare l'attività Di interoperabilità, che può eseguire attività WF3 dall'interno di un flusso di lavoro WF4. È consigliabile usare l'attività Interop solo quando necessario. Per altre informazioni sulla migrazione a WF4, vedere WF4 Migration Guidance (Indicazioni sulla migrazione di WF4).

Configurazione dell'ambiente

Configurazione dell'ambiente per il test delle prestazioni del flusso di lavoro

Risultati dei test

Nella tabella seguente vengono illustrati i risultati dell'esecuzione di un flusso di lavoro contenente cinque attività in una sequenza in varie configurazioni.

Prova Velocità effettiva (flussi di lavoro/sec)
Sequenza WF3 nel runtime di WF3 1,576
Sequenza WF3 nel runtime WF4 utilizzando Interop 2.745
La Sequenza WF4 153,582

Esiste un notevole aumento delle prestazioni nell'uso di Interop rispetto a utilizzare WF3 direttamente. Tuttavia, rispetto alle attività di WF4, l'aumento è trascurabile.

Riassunto

Gli ingenti investimenti nelle prestazioni per WF4 hanno dato i loro frutti in molte aree cruciali. Le prestazioni dei singoli componenti del flusso di lavoro sono in alcuni casi centinaia di volte più veloci in WF4 rispetto a WF3 a causa di un runtime WF più snello. Anche i numeri di latenza sono notevolmente migliori. Ciò significa che la riduzione delle prestazioni per l'uso di WF anziché i servizi di orchestrazione WCF con codifica manuale è molto piccola considerando i vantaggi aggiuntivi dell'uso di WF. Le prestazioni di persistenza sono aumentate di un fattore da 2,5 a 3,0. Il monitoraggio della salute tramite il tracciamento del flusso di lavoro ha ora molto poco sovraccarico. Sono disponibili un set completo di guide alla migrazione per coloro che stanno valutando il passaggio da WF3 a WF4. Tutto questo dovrebbe rendere WF4 un'opzione interessante per la scrittura di applicazioni complesse.