Set i Get

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…

Set

Aby dodać jakąś informację do Stanu Czasu musimy zrobić dwie rzeczy:

  1. informacja, którą zamierzamy dodać,
  2. unikalna nazwa (klucz) dla naszej informacji.

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.

Pobierz (Get)

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:intensityz 1000 na 3000 powyżej) lub Sonic PI zostanie zamknięty.

Wiele Wątków

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).

Prosty Deterministyczny System Stanu

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.