sabato 4 agosto 2018

Python vs Lua (2)

Nel post precedente abbiamo parlato di micropython e ci siamo lasciati con un micropython compilato per PC.
Oggi scopriamo che micropython, pur essendo tarato per girare su hardware ridottissimo, ha a disposizione anche funzionalità che non ti aspetteresti.
Ne vediamo, ad esempio due:
  • un sistema di gestione pacchetti tipo pip
  • e il modulo standard per i thread
Useremo entrambi per fare delle prove con mqtt

Partiamo dai thread

Micropython, battery-included non ha il tradizionale modulo standard multithreading bensì, al momento, ha solo il modulo base _thread con le API di basso livello
(uhm, chissà se il modulo _thread esiste su tutte le piattaforme supportate da micropython, io sono su linux: c'è posix sotto, è comunque una situazione favorita, sulle altre piattaforme sarà da verificare)
Comunque, anche se abbiamo solo _thread possiamo già fare qualche bel giochino

Prima di tutto, per non dover lavorare con _thread, definiamoci un modulo threading "hand-made" che che esponga l'API standard

Ecco qui:

import _thread
get_ident = _thread.get_ident

class Thread:

    def __init__(self, group=None, target=None, name=None, args=(), kwargs=None):
        self.target = target
        self.args = args
        self.kwargs = {} if kwargs is None else kwargs

    def start(self):
        self.running = _thread.allocate_lock()
        self.running.acquire()
        _thread.start_new_thread(self.run, ())

    def join(self):
        assert self.running.acquire()

    def run(self):
        self.target(*self.args, **self.kwargs)
        self.running.release()

salvandolo su un file con nome threading.py potremo banalmente utilizzarlo come se avessimo a disposizione effettivamente threading
(L'implementazione è molto banale e naive, mi sono ispirato ai sorgenti standard riducendoli drasticamente)

A questo punto siamo in grado di costruire il nostro primo test con i thread
(Notare che il modulo utime potrebbe non esserci su tutte le piattaforme oppure alcune piattaforme potrebbero disporre di moduli specifici esempio per la esp8266)

import utime
import threading

def target(name, count):
    for idx in range(count):
        utime.sleep(0.5)
        print("I'm {} - {}".format(name, threading.get_ident()))

def main():
    print("begin...")
    t = threading.Thread(target=target, args=("THREAD", 10))
    t.start()
    target("MAIN", 3)
    t.join()
    print("end.")

if __name__ == '__main__':
    main()

Salviamo con nome first_thread_test.py e lanciamo con micropython first_thread_test.py

Et, voilà! Abbiamo due thread che scrivono in modo un po' confuso sullo standard output
E' ora di alcune osservazioni conclusive

micropython funziona bene. In meno di 400K di eseguibile abbiamo a disposizione la grandissima parte del linguaggio (se ci pensate abbiamo utilizzato funzioni, classi, import di moduli...) ed una nutrita schiera di moduli della libreria standard.
L'esempio con i thread è uno dei più "cattivi" perché utilizza primitive di sistema operativo abbastanza specifiche. Nel nostro caso eravamo su un sistema posix e abbiamo potuto raggiungere egregiamente l'obiettivo

So far so good!

Vi avevo promesso prove con mqtt... e con Lua!... yes! Stay tuned! ;-)

Per non lasciarci con troppe cose in sospeso eccovi una chicca: micropython, per quanto ridotto ai minimi termini, dispone di un sistema di gestione dei pacchetti compatibile con pip.
E su PyPI ci sono tanti moduli specifici per micropython

Ecco ad esempio come installare un modulo ed utilizzarlo:

./micropython -m upip install micropython-pystone

(Il modulo, di default, finisce in $HOME/.micropython/lib)

L'esempio completo è qui

Nessun commento: