Il modulo xtime
Il modulo ntk.wrap.xtime (TODO: replicato in ntk.lib.xtime, perché? Da rimuovere?) risponde al problema dell'uso di sleep in un ambiente di multithread cooperativo.
Quando un microthread ha la necessità di attendere alcuni istanti prima di eseguire una certa azione, come lo fa?
Supponiamo si vuole attendere una certa condizione.
Può eseguire
while not my_condition(): pass
Questa è una cosidetta busy-wait. Il sistema viene appesantito, perché fino a quando la condizione non diventa vera il processo impegna la CPU.
Di norma si evita questo spreco inserendo dei piccoli sleep. Ad esempio
while not my_condition(): time.sleep(0.01)
Durante questa attesa la CPU non è impegnata. Soltanto una volta ogni 0.01 secondi, che per il processore è molto tempo, fa qualcosa per verificare se la condizione è divenuta vera.
Questa non è più una busy-wait, nel senso che l'intero sistema non viene appesantito. Ma in un ambiente di microthread cooperativi, questo approccio non istruisce lo schedulatore di passare il comando ad altri microthread. Così, anche se il sistema appare scarico, il nostro programma non va avanti.
Va quindi aggiunta una chiamata alla stackless.schedule, che nel nostro programma è nel metodo micro.micro_block().
while not my_condition(): time.sleep(0.01) micro.micro_block()
Nota: la chiamata a time.sleep resta necessaria, altrimenti ritorneremo ancora ad una situazione di busy-wait.
Qui ci si trova davanti ad una scelta. Quanto tempo aspettare nella chiamata bloccante time.sleep?
Se la verifica della condizione è molto impegnativa, allora un tempo basso nella sleep è controproducente per l'intero sistema. Infatti ogni pochi istanti la CPU viene impegnata per verificare la condizione, mentre forse sarebbe sufficiente al programma effettuare una verifica ad intervalli più ampi.
Si sarebbe portati quindi a usare un tempo alto nella sleep. Ma questa chiamata è bloccante per tutto il programma, quindi un tempo alto ostacola inutilmente il procedere degli altri microthread.
Se invece la verifica della condizione risultasse non impegnativa, allora usare un tempo basso sarebbe la risposta ottimale.
Il modulo xtime facilita questo lavoro implementando una funzione swait che automaticamente intervalla uno sleep di 0.001 secondi con una chiamata micro_block fino a quando non è passato il tempo richiesto. La verifica da fare è poco onerosa, si tratta di leggere l'ora del sistema.
Notare inoltre che nel modulo xtime sia la funzione swait sia la funzione time usano come unità il millisecondo, invece del secondo come nel modulo standard time. (TODO: C'è un motivo particolare?)
In conclusione:
se la condizione da verificare è poco onerosa, intervallarla con una chiamata a time.sleep con un tempo basso espresso in secondi e una chiamata a micro_block;
se la condizione da verificare è molto onerosa, intervallarla con una chiamata a xtime.swait con un tempo più alto espresso in millisecondi;
se non ci sono condizioni da verificare, ma solo si vuole attendere un certo tempo, usare xtime.swait con il tempo esatto che si vuole attendere espresso in millisecondi.