Miglioramento delle prestazioni

Miglioramento delle prestazioni in Hilo (app di Windows Store in C++ e XAML)

[ Questo articolo è rivolto agli sviluppatori per Windows 8.x e Windows Phone 8.x che realizzano app di Windows Runtime. Gli sviluppatori che usano Windows 10 possono vedere Documentazione aggiornata ]

Da: Sviluppo di un'app di Windows Store end-to-end con C++ e XAML: Hilo

Logo Patterns & Practices

Pagina precedente | Pagina successiva

Il team di Hilo C++ ha impiegato molto tempo per determinare cosa funziona e cosa no per la compilazione di un'app veloce e fluida. Abbiamo identificato le aree dell'app in cui era opportuno migliorare le prestazioni percepite e quelle in cui dovevamo migliorare le prestazioni effettive. Di seguito sono riportati alcuni suggerimenti e linee guida per creare un'app con prestazioni e velocità di risposta ottimali.

Download

Scarica l'esempio di Hilo
Download guida (PDF)

Dopo aver scaricato il codice, per le istruzioni vedi Introduzione a Hilo.

In questo articolo verranno illustrati gli argomenti seguenti

  • Differenze tra prestazioni effettive e prestazioni percepite.
  • Strategie consigliate per la creazione del profilo di un'app.
  • Suggerimenti per creare un'app veloce e fluida.
  • Come garantire la velocità di risposta dell'interfaccia utente dell'app mediante l'esecuzione delle operazioni che richiedono un utilizzo intensivo dei calcoli in un thread in background.

Si applica a

  • Windows Runtime per Windows 8
  • Estensioni del componente Visual C++ (C++/CX)
  • XAML

Miglioramento delle prestazioni con il profiling dell'app

Per quanto riguarda le app, gli utenti hanno diverse aspettative. Desiderano risposte immediate a tocco, clic, gesti e pressioni di tasti. Si aspettano che le animazioni siano uniformi e fluide e che l'app risponda in tempo reale agli input.

I problemi di prestazioni si riscontrano in vari modi. Possono ridurre la durata della batteria, provocare ritardi nelle operazioni di panning e scorrimento o persino far sembrare l'app bloccata per un determinato periodo di tempo. Una tecnica per determinare il punto in cui le ottimizzazioni del codice garantiscono un effetto maggiore ai fini della riduzione dei problemi di prestazioni è eseguire il profiling dell'app.

Gli strumenti di profiling per le app di Windows Store consentono di misurare, valutare e individuare i problemi relativi alle prestazioni nel tuo codice. Il profiler raccoglie le informazioni relative ai tempi delle app mediante un metodo di campionamento che raccoglie le informazioni relative allo stack di chiamate della CPU a intervalli regolari. I rapporti sulla profilatura presentano informazioni sulle prestazioni dell'app e ti consentono di visualizzare i percorsi di esecuzione del codice e il costo di esecuzione delle funzioni del codice in modo da poter individuare le migliori opportunità per l'ottimizzazione. Per ulteriori informazioni, vedi Come eseguire il profiling del codice Visual C++, Visual C# e Visual Basic nelle app di Windows Store in un computer locale. Per informazioni su come analizzare i dati restituiti dal profiler, vedi Analisi dei dati delle prestazioni per il codice Visual C++, Visual C# e Visual Basic nelle app di Windows Store.

L'ottimizzazione delle prestazioni va oltre l'implementazione di algoritmi efficienti. È possibile pensare alle prestazioni come alla percezione dell'utente circa le prestazioni dell'app mentre la utilizza. L'esperienza utente relativa all'app può essere suddivisa in tre categorie: percezione, tolleranza e velocità di risposta.

  • Percezione. La percezione delle prestazioni di un utente può essere definita in base a quanto favorevole è il ricordo del tempo impiegato per svolgere le attività all'interno dell'app. Non sempre questa percezione corrisponde alla realtà. Le prestazioni percepite possono essere migliorate mediante la riduzione della quantità di tempo intercorso tra le operazioni che l'utente deve eseguire per completare le attività necessarie in un'app.
  • Tolleranza. La tolleranza di un utente in merito al ritardo dipende dal tempo che l'utente prevede sia necessario per l'esecuzione di un'operazione. Ad esempio, un utente potrebbe considerare i tempi necessari per un'operazione di ritaglio di un'immagine intollerabili se l'app durante il processo di ritaglio non risponde anche solo per pochi secondi. La tolleranza di un utente nei confronti del ritardo può essere aumentata identificando le aree dell'app che richiedono tempi di elaborazione significativi e limitando o eliminando l'incertezza dell'utente durante queste situazioni fornendo un'indicazione visiva dello stato di avanzamento. È inoltre possibile usare le API asincrone per evitare il blocco del thread dell'interfaccia utente e l'impressione che l'app sia bloccata.
  • Velocità di risposta. La velocità di risposta è relativa all'attività svolta. Per misurare e classificare le prestazioni di un'attività, deve essere presente un intervallo di tempo con cui effettuare il confronto. Il team Hilo ha usato l'euristica in base a cui se un'attività impiega più di 500 ms, l'app deve fornire all'utente un feedback sotto forma di indicazione visiva dello stato di avanzamento.

Suggerimenti per il profiling

Quando esegui il profiling dell'app, segui questi suggerimenti al fine di raccogliere misurazioni affidabili e ripetibili sulle prestazioni:

  • Windows 8 viene eseguito in un'ampia gamma di dispositivi, pertanto misurare le prestazioni su un elemento hardware non sempre consente di mostrare e determinare le caratteristiche delle prestazioni di altri fattori di forma.
  • Accertati che il computer usato per l'acquisizione delle misurazioni delle prestazioni sia collegato alla rete elettrica e non alimentato a batteria. Molti sistemi risparmiano energia quando sono alimentati a batteria, pertanto operano in modo diverso.
  • Verifica che l'utilizzo di memoria totale del sistema sia inferiore al 50%. Se è superiore, chiudi le app fino a quando non raggiungi il 50% per assicurarti di misurare l'impatto della tua app e non quello di altri processi.
  • Durante l'esecuzione del profiling di un'app in modalità remota, ti consigliamo di interagire con l'app direttamente nel dispositivo remoto. Puoi interagire con l'app mediante Connessione Desktop remoto, tuttavia, questa soluzione può alterare in modo significativo le prestazioni della tua app e i dati delle prestazioni raccolti. Per ulteriori informazioni, vedi Come eseguire il profiling del codice Visual C++, Visual C# e Visual Basic nelle app di Windows Store in un computer remoto.
  • Per raccogliere i risultati delle prestazioni più accurati, esegui il profiling di una versione compilata della tua app. Vedi How to: Impostare configurazioni di debug e rilascio.
  • Evita di eseguire il profiling dell'app nel simulatore in quanto il simulatore può alterare le prestazioni dell'app.

Altri strumenti per le prestazioni

Oltre agli strumenti di profiling per misurare le prestazioni dell'app, il team Hilo ha usato anche Monitoraggio affidabilità e Performance Monitor Windows (perfmon). È possibile usare Perfmon per esaminare in che modo i programmi che esegui influiscono sulle prestazioni del computer, sia in tempo reale che raccogliendo dati di registro per l'analisi successiva. Il team Hilo ha usato questo strumento per effettuare una diagnosi generale delle prestazioni dell'app. Per altre informazioni su perfmon, vedi Monitoraggio affidabilità e Performance Monitor Windows.

[Torna all'inizio]

Suggerimenti per le prestazioni

Il team di Hilo ha impiegato molto tempo per determinare cosa funziona e cosa no per la compilazione di un'app veloce e fluida. Di seguito vengono indicati alcuni punti da ricordare.

Prevedere tempi di avvio dell'app veloci

Evita il caricamento di oggetti in memoria di grandi dimensioni durante l'attivazione dell'app. Se devi completare attività di grandi dimensioni, imposta una schermata iniziale personalizzata in modo che l'app possa svolgere tali attività in background.

Aumentare la velocità di risposta nelle app usando chiamate ad API asincrone nel thread dell'interfaccia utente

Non bloccare il thread dell'interfaccia utente con API sincrone. Usa piuttosto API asincrone o chiama API sincrone in un contesto non bloccante. Valuta inoltre lo spostamento delle operazioni con un utilizzo di elaborazione intensivo in un thread pool di thread. Si tratta di un aspetto importante in quanto è probabile che gli utenti notino ritardi superiori a 100 ms. Le operazioni con un utilizzo di elaborazione intensivo devono essere suddivise in una serie di operazioni più piccole per consentire al thread dell'interfaccia utente di ascoltare l'input dell'utente che avviene nel frattempo.

Usare le anteprime per eseguire rapidamente il rendering

Il file system e i file multimediali rappresentano una parte importante della maggior parte delle app e anche una delle origini più comuni dei problemi relativi alle prestazioni. L'accesso ai file è in genere uno dei colli di bottiglia principali delle prestazioni per le app che presentano visualizzazioni con raccolte di file, ad esempio gli album fotografici. L'accesso alle immagini può risultare lento in quanto necessita di memoria e cicli di CPU per archiviare, decodificare e visualizzare l'immagine.

Anziché ridimensionare un'immagine a dimensioni intere da visualizzare come anteprima, usa le API per la creazione di anteprime di Windows Runtime. Windows Runtime offre una serie di API supportate da una cache efficiente che consentono all'app di ottenere rapidamente una versione più piccola di un'immagine da usare come anteprima.

Eseguire la prelettura delle anteprime

Oltre a fornire le API per il recupero delle anteprime, nelle API di Windows Runtime è anche incluso un metodo SetThumbnailPrefetch. Questo metodo specifica l'anteprima da recuperare per ogni file o cartella in base allo scopo dell'anteprima, alle dimensioni necessarie e al comportamento desiderato da usare per recuperare l'immagine di anteprima.

In Hilo la classe FileSystemRepository interroga il file system per ottenere le foto che soddisfano un criterio di data specifico e restituisce tutte le foto che soddisfano tale criterio. Il metodo CreateFileQuery usa il metodo SetThumbnailPrefetch per restituire le anteprime per i file nel set di risultati della query.

FileSystemRepository.cpp


inline StorageFileQueryResult^ FileSystemRepository::CreateFileQuery(IStorageFolderQueryOperations^ folder, String^ query, IndexerOption indexerOption)
{
    auto fileTypeFilter = ref new Vector<String^>(items);
    auto queryOptions = ref new QueryOptions(CommonFileQuery::OrderByDate, fileTypeFilter);
    queryOptions->FolderDepth = FolderDepth::Deep;
    queryOptions->IndexerOption = indexerOption;
    queryOptions->ApplicationSearchFilter = query;
    queryOptions->SetThumbnailPrefetch(ThumbnailMode::PicturesView, 190, ThumbnailOptions::UseCurrentScale);
    queryOptions->Language = CalendarExtensions::ResolvedLanguage();
    return folder->CreateFileQueryWithOptions(queryOptions);
}


In questo caso, il codice esegue la prelettura delle anteprime che visualizzano un'anteprima di ogni foto, con una larghezza massima di 190 pixel e aumenta le dimensioni dell'anteprima richieste in base alla risoluzione in PPI (pixel per pollice) dello schermo. L'uso del metodo SetThumbnailPrefetch può determinare un miglioramento del 70% in merito al tempo impiegato per mostrare una visualizzazione delle foto dalla raccolta di immagini dell'utente.

Tagliare i dizionari delle risorse

Le risorse a livello di app devono essere archiviate nell'oggetto Application per evitare la duplicazione, ma è consigliabile spostare le risorse specifiche delle singole pagine nel dizionario delle risorse della pagina.

Ottimizzare il numero di elementi

Il framework XAML è progettato per visualizzare migliaia di oggetto, tuttavia, la riduzione del numero di elementi in ogni pagina migliora la velocità del rendering dell'app. Puoi ridurre il numero di elementi di una pagina evitando gli elementi non necessari e comprimendo gli elementi che non sono visibili.

Usare animazioni indipendenti

Un'animazione indipendente viene eseguita indipendentemente dal thread dell'interfaccia utente. Molti tipi di animazione usati in XAML sono costituiti da un motore di composizione che viene eseguito in un thread separato e che sposta le attività del motore dalla CPU alla GPU. Lo spostamento della composizione dell'animazione in un thread diverso da quello dell'interfaccia utente significa che l'animazione non risulterà disturbata o sarà bloccata dall'app che lavora sul thread dell'interfaccia utente. La composizione dell'animazione sulla GPU migliora le prestazioni in modo significativo poiché consente l'esecuzione delle animazioni con una frequenza dei fotogrammi uniforme e coerente.

Non è necessario un markup aggiuntivo per rendere indipendenti le animazioni. Il sistema determina quando è possibile comporre l'animazione in modo indipendente anche se per le animazioni indipendenti esistono alcuni limiti. Ecco alcuni problemi comuni.

  • L'animazione delle proprietà Height e Width di un elemento UIElement determina un'animazione indipendente in quanto queste proprietà richiedono modifiche del layout che possono essere eseguite sono nel thread dell'interfaccia utente. Per ottenere un effetto simile a quello dell'animazione di Height o Width, puoi animare la scala del controllo.
  • Se imposti la proprietà CacheMode di un elemento su BitmapCache tutte le animazioni del sottoalbero visivo vengono eseguite in modo indipendente. La soluzione è di non animare il contenuto memorizzato nella cache.
  • I controlli ProgressRing e ProgressBar dispongono di infinite animazioni che possono continuare a essere eseguite anche se il controllo non è visibile nella pagina, evitando così che la CPU passi alla modalità di risparmio energia minimo o di inattività. Imposta le proprietà ProgressRing::IsActive e ProgressBar::IsIndeterminate su false quando non sono visualizzate nella pagina.

Hilo usa il tipo ObjectAnimationUsingKeyFrames che è un'animazione indipendente.

Usare modelli paralleli nei calcoli pesanti

Se la tua app esegue calcoli pesanti, è probabile che tu debba usare tecniche di programmazione parallela. Esistono numerosi modelli già definiti per usare in modo efficace l'hardware multicore. Programmazione parallela con Microsoft Visual C++ è una risorsa contenente alcuni dei modelli più comuni, con esempi che utilizzano la raccolta di modelli paralleli (Parallel Patterns Library, PPL) e la raccolta di agenti asincroni. Per la documentazione completa relativa alle API e agli esempi, vedi Runtime di concorrenza.

Hilo contiene alcune operazioni con un utilizzo intensivo di elaborazione per la modifica delle immagini. Per queste operazioni abbiamo usato tecniche di programmazione parallela per usare al meglio l'hardware di elaborazione parallela del computer. Per altre informazioni, vedi Adattamento alla programmazione asincrona, Uso della programmazione parallela e delle attività in background e Modelli di programmazione asincrona in C++ in questa guida.

Prestare attenzione al sovraccarico per la conversione dei tipi

Per interagire con le funzionalità di Windows Runtime è talvolta necessario creare tipi di dati dagli spazi dei nomi Piattaforma e Windows. In alcuni casi, la creazione di oggetti di questi tipi comporta un sovraccarico per la conversione dei tipi. Hilo esegue la conversione dei tipi a livello di interfaccia ABI (Abstract Binary Interface) per ridurre al minimo il sovraccarico. Per altre informazioni, vedi Scrittura di codice C++ moderno in questa guida.

Usare tecniche per la riduzione dei costi di marshaling

Se il tuo codice comunica con linguaggi diversi da C++ e XAML, è possibile che tu debba sostenere i costi di marshaling dei dati tra più ambienti di runtime. Hilo interagisce solo con C++ e XAML, quindi non abbiamo dovuto tenere conto di questo aspetto. Per altre informazioni, vedi Scrittura di codice C++ moderno in questa guida.

Mantenere un utilizzo della memoria basso quando l'app è in modalità di sospensione

Quando l'app si riattiva dopo la sospensione, viene visualizzata quasi istantaneamente. Ma quando l'app viene riavviata dopo essere stata terminata, potrebbe essere necessario più tempo prima che venga visualizzata. Di conseguenza, evitare che l'app venga terminata quando è sospesa è una delle tecniche disponibili per gestire la percezione e la tolleranza dell'utente in merito alla velocità di risposta dell'app. A questo scopo, ti consigliamo di mantenere un utilizzo della memoria basso quando l'app è sospesa.

Quando l'app inizia il processo di sospensione, deve liberare gli oggetti di grandi dimensioni che possono essere facilmente ricostruiti alla riattivazione. Questo consente di mantenere basso il footprint di memoria e ridurre la probabilità che il sistema operativo termini l'app dopo la sospensione. Per altre informazioni, vedi Gestione di sospensione, ripresa e attivazione.

Ridurre al minimo la quantità di risorse usate dall'app suddividendo le operazioni di elaborazione intensive in operazioni di dimensioni più piccole

Windows deve gestire le esigenze in termini di risorse di tutte le app Windows Store terminando le app sospese per consentire l'esecuzione di altre app. Un effetto collaterale che si determina è che se la tua app richiede un'elevata quantità di memoria, altre app possono essere terminate anche se l'app libera la memoria poco tempo dopo averla richiesta. Rispetta gli altri in modo che l'utente non inizi ad attribuire eventuali latenze percepite nel sistema alla tua app. A questo scopo, puoi suddividere le operazioni di elaborazione intensive in una serie di operazioni di dimensioni più piccole.

[Torna all'inizio]

 

 

Mostra:
© 2017 Microsoft