Ottimizzazioni

MicroPython utilizza diverse ottimizzazioni per risparmiare RAM ma anche per garantire l’esecuzione efficiente dei programmi. Questo capitolo illustra alcune di queste ottimizzazioni.

Nota

L’interning delle stringhe in MicroPython e Mappe e dizionari descrivono in dettaglio altre ottimizzazioni su stringhe e dizionari.

Bytecode congelato

Quando MicroPython carica codice Python dal filesystem, deve prima analizzare il file in una rappresentazione temporanea in memoria, e quindi generare bytecode per l’esecuzione, entrambi memorizzati nell’heap (nella RAM). Questo può portare all’uso di quantità significative di memoria. Il cross compiler di MicroPython può essere usato per generare un file .mpy, contenente il bytecode precompilato di un modulo Python. Questo verrà comunque caricato nella RAM, ma evita l’overhead aggiuntivo della fase di parsing.

Come ulteriore ottimizzazione, il bytecode precompilato di un file .mpy può essere «congelato» nell’immagine del firmware come parte del processo principale di compilazione del firmware, il che significa che il bytecode verrà eseguito dalla ROM. Questo può portare a un significativo risparmio di memoria e ridurre la frammentazione dell’heap.

Vedi File manifest di MicroPython per maggiori informazioni.

Variabili

MicroPython elabora le variabili locali e globali in modo diverso. Le variabili globali vengono memorizzate e cercate in un dizionario globale allocato sull’heap (nota che ogni modulo ha il proprio dict separato, quindi un namespace separato). Le variabili locali, invece, vengono memorizzate sullo stack dei valori di Python, che può risiedere sullo stack C o sull’heap. Esse vengono accedute direttamente tramite il loro offset all’interno dello stack di Python, il che è più efficiente di una ricerca globale in un dict.

Anche la lunghezza dei nomi delle variabili globali influisce sulla quantità di RAM usata, poiché gli identificatori vengono memorizzati nella RAM. Più corto è l’identificatore, meno memoria viene usata.

L’altro aspetto è che le variabili const che iniziano con un underscore vengono trattate come vere costanti e non vengono allocate o aggiunte in un dizionario, risparmiando così un po” di memoria. Queste variabili usano const() dalla libreria di MicroPython. Pertanto:

from micropython import const

X = const(1)
_Y = const(2)
foo(X, _Y)

Si compila in:

X = 1
foo(1, 2)

Allocazione di memoria

La maggior parte dei costrutti comuni di MicroPython non viene allocata sull’heap. Tuttavia i seguenti lo sono:

  • Strutture dati dinamiche come liste, mappature, ecc.;

  • Funzioni, classi e istanze di oggetti;

  • import; e

  • Prima assegnazione di variabili globali (per creare lo slot nel dict globale).

Per una discussione dettagliata su una prospettiva più orientata all’utente riguardo all’ottimizzazione, vedi Massimizzare la velocità di MicroPython.