Quando il proprio software si blocca: migliorare le prestazioni in modo sistematico

CAD-Modell eines Maschinenbauteils auf einem Bildschirm vor einem steil ansteigenden Leistungsdiagramm

Qualità e sicurezza

Il software è cresciuto nel corso degli anni, ogni versione ha portato nuove funzioni. A un certo punto, con file di grandi dimensioni, gli utenti attendono una risposta per minuti e la finestra mostra «Non risponde». Singole ottimizzazioni fatte a sensazione aiutano allora di rado. Serve un approccio sistematico.

Prima misurare, poi modificare

La causa più frequente di un'ottimizzazione inutile è tirare a indovinare. Misuri prima, e precisamente con dati realistici: con le grandi costruzioni, serie di misure o progetti per i quali i Suoi utenti attendono davvero. Un profiler, ad esempio il profiler delle prestazioni di Visual Studio, mostra dove se ne va davvero il tempo. Registri una misura di partenza per tre-cinque processi tipici. Solo così potrà dimostrare in seguito che cosa ha prodotto una misura.

Raccogliere e ordinare i punti di intervento

In un software cresciuto nel tempo raramente c'è un unico freno. Per lo più sono molti punti che si sommano. Li raccolga in un documento di concetto e valuti ciascuno per effetto e impegno. Candidati tipici sono:

Punto di interventoSintomo tipicoMisura possibile
Calcolo lungo nel thread UI La finestra si blocca Spostare il calcolo in background
Calcolo ripetuto Lo stesso risultato viene ricalcolato a ogni ridisegno Memorizzare i risultati, ricalcolare solo in caso di modifiche
Struttura dati inadatta Il tempo di esecuzione cresce in modo sproporzionato con la quantità di dati Ricerca tramite dictionary o indice spaziale invece che in lunghe liste
Molti piccoli accessi Singoli accessi a database o file all'interno di cicli Raggruppare gli accessi
Ridisegno continuo L'interfaccia si aggiorna a ogni singola modifica Raccogliere le modifiche, aggiornare una volta
Pressione sulla memoria Molti oggetti di breve durata, frequente garbage collection Riutilizzare gli oggetti, evitare copie inutili

Attui per primi i punti più efficaci e misuri di nuovo dopo ogni passo.

Calcolare in background

Non ogni calcolo si può accelerare. Ma quasi ogni calcolo si può organizzare in modo che l'utente possa continuare a lavorare. In .NET ci si riesce con async e await: il calcolo gira in un thread in background, l'interfaccia resta utilizzabile e il risultato torna poi nel thread UI. Un esempio per WPF:

private CancellationTokenSource abbruch;



private async void BerechnenButton_Click(object sender, RoutedEventArgs e)

{

    berechnenButton.IsEnabled = false;

    abbruch = new CancellationTokenSource();

    var fortschritt = new Progress<int>(prozent => fortschrittsBalken.Value = prozent);

    try

    {

        // Copiare i dati nel thread UI, in background calcolare solo con la copia

        ModellDaten daten = modell.ErstelleKopie();

        Ergebnis ergebnis = await Task.Run(

            () => Berechnung.Starte(daten, fortschritt, abbruch.Token));

        ZeigeErgebnis(ergebnis);

    }

    catch (OperationCanceledException)

    {

        statusText.Text = "Berechnung abgebrochen.";

    }

    finally

    {

        berechnenButton.IsEnabled = true;

    }

}



private void AbbrechenButton_Click(object sender, RoutedEventArgs e)

{

    abbruch?.Cancel();

}

Importante: in background il calcolo non deve toccare né i controlli né il database dei disegni di un sistema CAD. Lavora su una copia dei dati necessari e restituisce il suo risultato. L'avanzamento lo segnala tramite IProgress<T>. Poiché l'oggetto Progress è stato creato nel thread UI, ogni segnalazione arriva lì. L'annullamento il calcolo lo verifica regolarmente tramite il CancellationToken.

Dalla pratica: da 12,5 a 15 volte più veloce

Un'azienda aveva sviluppato da sé il proprio sistema CAD e lo aveva ampliato nel corso degli anni con moltissime funzioni. Con costruzioni di una certa dimensione si attendevano diversi minuti per una risposta – il sistema era praticamente bloccato. L'obiettivo del cliente era raddoppiare la velocità.

Abbiamo esaminato il software e annotato i punti di intervento in un documento di concetto. Arrivati a quasi 50 punti abbiamo smesso di contare. Le misure più efficaci le abbiamo attuate noi stessi. Il reparto software del cliente lo abbiamo guidato in diverse riunioni ad attuare da sé gli altri punti. I calcoli onerosi ora girano in background. Il risultato: invece del raddoppio sperato, il sistema è da 12,5 a 15 volte più veloce, misurato sugli stati intermedi. Dove si calcola in background, gli utenti non percepiscono più alcun ritardo.

Errori tipici

  • Ottimizzare senza misurare. Chi tira a indovinare migliora spesso punti che costano pochissimo tempo.
  • Misurare con piccoli dati di test. Molti freni si manifestano solo con grandi quantità di dati.
  • Bloccarsi in attesa del risultato invece di attenderlo con await. .Result o .Wait() nel thread UI bloccano di nuovo l'interfaccia e possono causare deadlock.
  • async void al di fuori dei gestori di eventi. Lì le eccezioni non si possono intercettare. Altrimenti usi async Task.
  • Accedere dal background all'interfaccia o al database CAD. Ciò porta a crash sporadici difficili da trovare.
  • Non continuare a verificare dopo l'ottimizzazione. Senza misure ripetute o test automatizzati il software, con le versioni successive, torna inosservato a rallentare.
  • Lasciare il know-how al fornitore. Se il Suo team capisce perché qualcosa è diventato più veloce, il software resta veloce anche in futuro.

Come La aiutiamo

Fonti: caso di studio «Sistema CAD proprietario: da 12,5 a 15 volte più veloce», Casi di studio Cadida; Microsoft Learn: programmazione asincrona con async e await.

CONTACT

Seleziona la tua lingua

Primo colloquiofissare oraPrimo colloquiofissare ora