Sonic Pi posiada globalny magazyn pamięci nazywany Stanem Czasu. Dwie podstawowe operacje jakie możesz na nim wykonywać to ustawienie informacji (set
) oraz pobranie informacji (get
). Zanurzmy się głębiej…
Aby dodać jakąś informację do Stanu Czasu musimy zrobić dwie rzeczy:
Na przykład, możemy chcieć zachować liczbę 3000
pod kluczem :intensity
(intensywność). Można to zrobić używając funkcji set
:
set :intensity, 3000
Możemy użyć dowolnej nazwy dla naszego klucza (key). Jeśli jakaś informacja została już zapisana pod tym kluczem, nasze nowe ustawienie (set
) nadpisze je:
set :intensity, 1000
set :intensity, 3000
W powyższym przykładzie, jako że zapisaliśmy obie liczby pod tym samym kluczem, ostanie uruchomienie funkcji set
‘wygrywa’. Wynika z tego, że liczba powiązana z :intensity
będzie wynosić 3000
ponieważ pierwsze wywołanie funkcji set
zostało efektywnie nadpisane.
Aby pobrać informację ze Stanu Czasu (Time State) potrzebujemy tylko klucza, którego użyliśmy do ustawienia go za pomocą funkcji set
, w naszym przypadku jest to :intensity
Następnie musimy tylko uruchomić polecenie get[:intensity]
i będziemy mogli podejrzeć tę wartość poprzez wyświetlenie wyniku w panelu z logami:
print get[:intensity] #=> prints 3000
Zauważ, że odwołanie do get
może zwrócić informację która została ustawiona (set
) w poprzednim uruchomieniu. Gdy już raz pewna informacja zostanie ustawiona za pomocą polecenia set
staje się ona dostępna dopóki nie zostanie nadpisana (dokładnie tak samo jak zmieniliśmy wartość dostępną pod symbolem:intensity
z 1000
na 3000
powyżej) lub Sonic PI zostanie zamknięty.
Podstawową korzyścią systemu Stanu Czasu (Time State) jest to, że może być on bezpiecznie używany pomiędzy różnymi wątkami oraz żywymi pętlami. Na przykład, możesz mieć jedną żywą pętlę, która ustawia pewną informację oraz inną, która ją wyciąga:
live_loop :setter do
set :foo, rrand(70, 130)
sleep 1
end
live_loop :getter do
puts get[:foo]
sleep 0.5
end
Ogromną zaletą korzystania z funkcji set
i get
w różnych wątkach jest fakt, że zawsze dają one ten sam wynik przy uruchomieniu przycisku ‘Run’. Dalej, spróbuj sam. Sprawdź czy dostaniesz taki sam rezultat w swoich logach:
{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
Spróbuj uruchomić to kilkukrotnie - zauważ, że za każdym razem wynik jest taki sam. To jest właśnie coś co nazywamy zachowaniem deterministycznym. Jest to bardzo ważne gdy chcemy podzielić się naszą muzyką jako kodem. Zależy nam na tym aby osoba uruchamiająca nasz kod usłyszała dokładnie to co chcieliśmy aby usłyszała (dokładnie tak samo jak z odtworzeniem utworu MP3 czy stream’a z dźwiękiem w internecie brzmi identycznie dla każdego ze słuchaczy).
Wcześniej w Sekcji 5.6 rozważaliśmy dlaczego wykorzystywanie zmiennych w różnych wątkach może prowadzić do nieoczekiwanych zachowań. Powoduje to, że nie jesteśmy w stanie wiarygodnie odtworzyć kod taki jak ten:
## An Example of Non-Deterministic Behaviour
## (due to race conditions caused by multiple
## live loops manipulating the same variable
## at the same time).
##
## If you run this code you'll notice
## that the list that's printed is
## not always sorted!
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
Spróbujmy zobaczyć jak mogłoby to wyglądać gdybyśmy użyli funkcji get
i set
:
## An Example of Deterministic Behaviour
## (despite concurrent access of shared state)
## using Sonic Pi's new Time State system.
##
## When this code is executed, the list that's
## printed is always sorted!
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
Zauważ, że ten kod jest prawie identyczny z wersją, w której używaliśmy wcześniej zmiennej. Jednakże, kiedy uruchomisz ten kod, zacznie się on zachowywać tak jakbyś tego oczekiwał od typowego kodu Sonic Pi - w tym wypadku za każdym razem jest wykonywana ta sama rzecz, wszystko dzięki systemowi Stanu Czasu (Time State).
Dlatego, gdy współdzielimy informację pomiędzy różnymi żywymi pętlami i wątkami, używajmy funkcji get
i set
zamiast zmiennych aby otrzymać deterministyczne i powtarzalne zachowanie.