Sonic Pi ha un archivio globale di memoria chiamato Time State. Le due cose principali che fai con questo sono set
(impostare) e get
(richiamare) informazioni. Immergiamoci di più…
Per impostare informazioni nel Time State abbiamo bisogno di due cose:
Per esempio, forse vogliamo impostare il numero 3000
sotto la chiave :intensity
. Questo è possibile utilizzano la funzione set
:
set :intensity, 3000
Possiamo usare qualsiasi nome per la chiave. Se si sono già impostate informazioni con quella chiave, il nuovo set
le sostituisce:
set :intensity, 1000
set :intensity, 3000
Nell’esempio sopra, visto che abbiamo memorizzato tutti e due i numeri sotto la stessa chiave, “vince” l’ultima chiamata di set
, così il numero associato con :intensity
sarà 3000
perché la prima chiamata di set
è in effetti soprascritta.
Per recuperare informazioni dal Time State abbiamo bisogno solamente della chiave usata per fare il set
; in questo caso, :intensity
. Poi, basta che chiamiamo get[:intensity]
, che possiamo verificare facilmente stampandone il risultato sul log:
print get[:intensity] #=> stampa 3000
Nota che le chiamate a get
possono restituire informazioni che erano set
da una esecuzione precedente. Una volta impostata una informazione con set
, è disponibile fino a quando non viene soprascritta (come sopra abbiamo rimpiazzato il valore 1000
di :intensity
con 3000
) o fino a quando non viene chiuso Sonic Pi.
Il beneficio principale del sistema Time State è che si può usare senza rischi attraverso thread o cicli vivi. Per esempio, puoi avere un ciclo vivo che imposta informazioni ed un altro che le recupera:
live_loop :setter do
set :foo, rrand(70, 130)
sleep 1
end
live_loop :getter do
puts get[:foo]
sleep 0.5
end
Una cosa bella dell’uso di get
e set
in questo modo attraverso i thread è che genera sempre lo stesso risultato ogni volta che premi “Run”. Dai, provalo. Vedi se ottieni il seguente nel tuo log:
{run: 0, time: 0.0}
└─ 125.72265625
{run: 0, time: 0.5}
└─ 125.72265625
{run: 0, time: 1.0}
└─ 76.26220703125
{run: 0, time: 1.5}
└─ 76.26220703125
{run: 0, time: 2.0}
└─ 114.93408203125
{run: 0, time: 2.5}
└─ 114.93408203125
{run: 0, time: 3.0}
└─ 75.6048583984375
{run: 0, time: 3.5}
└─ 75.6048583984375
Prova ad eseguire alcune volte — vedi, è uguale ogni volta. Questo si chiama comportamento deterministico ed è importantissimo quando vogliamo condividere la nostra musica in forma di codice e sapere che la persona che la esegue sente esattamente quello che abbiamo voluto che sentisse (come un MP3 o un flusso di internet suona lo stesso per tutti gli ascoltatori).
Nella Sezione 5.6 abbiamo parlato della ragione perché usare variabili attraverso thread può causare comportamento casuale. Questo ci blocca da potere riprodurre code come questo in maniera affidabile:
## Un Esempio di Comportamento Non-Deterministico
## (dovuto a condizioni di gara causate da vari
## cicli vivi che manipolano lo stesso variabile allo
## stesso tempo).
##
## Se esegui questo codice noterai
## che l'elenco che viene stampato non
## è sempre in ordine!
a = (ring 6, 5, 4, 3, 2, 1)
live_loop :shuffled do
a = a.shuffle
sleep 0.5
end
live_loop :sorted do
a = a.sort
sleep 0.5
puts "sorted: ", a
end
Guardiamo come possiamo fare questo con get
e set
:
## Un Esempio di Comportamento Deterministico
## (nonostante accesso concorrente dello
## stato condiviso) usando il nuovo sistema
## Time State di Sonic Pi.
##
## Quando questo codice si esegue, l'elenco che
## viene stampato è sempre in ordine!
##
set :a, (ring 6, 5, 4, 3, 2, 1)
live_loop :shuffled do
set :a, get[:a].shuffle
sleep 0.5
end
live_loop :sorted do
set :a, get[:a].sort
sleep 0.5
puts "sorted: ", get[:a]
end
Nota che questo codice è quasi uguale alla versione prima che usava un variabile. Ma quando esegui questo codice, si comporta come si aspetta con qualsiasi codice tipico di Sonic Pi — fa la stessa cosa ogni volta in questo caso, grazie al sistema Time State.
Dunque, quando si condividono informazioni fra cicli vivi e thread, usa get
e set
invece di variabili per avere comportamento deterministico e riproducibile.