Sonic Pi heeft een globaal memory model genaamd tijd toestand. De twee belangrijkste dingen die je ermee doet is informattie zetten
(set) en ophalen
(get). Laten we erin duiken…
Om informatie op te slaan in de tijd toestand hebben we twee dingen nodig:
We willen bijvoorbeeld het getal 3000
opslaan met de sleutel :intensiteit
. Dit is mogelijk door de set
functie te gebruiken:
set :intensiteit, 3000
We kunnen elke naam gebruiken voor onze sleutel. Wanneer informatie al was opgeslagen voor die sleutel, dan overschrijft de nieuwe set
die:
set :intensiteit, 1000
set :intensiteit, 3000
In het bovenstaande voorbeeld hebben we beide getallen opgeslagen onder dezelfde sleutel. De laatste aanroep van set
‘wint’. Het getal dat gekoppeld is aan :intensiteit
zal 3000
zijn omdat de eerste aanroep van set
effectief wordt overschreven.
Om informatie op te halen uit de tijd toestand hebben we allen de sleuten nodig die werd gebruikt om voor set
. In ons geval is dat :intensiteit
. We hoeven alleen get[:intensiteit]
aan te roepen wat we kunnen zien door het resultaat naar het log af te drukken:
print get[:intensiteit] #=> print 3000
Merk op dat aanroepen van get
informatie kunnen teruggeven die was geset
in de vorige uitvoering. Wanneer een stuk informatie is geset
is het beschikbaar totdat of de informatie is overschreven (net als de aanpassing van :intensiteit
van de waarde 1000
naar 3000
hierboven) of Sonic Pi is afgesloten.
Het belangrijkste voordeel van het tijd toestand systeem is dat het veilig gebruikt kan worden tussen meerdere threads of live lussen. Je kunt bijvoorbeeld een live lus hebben voor het zetten van informatie en een andere voor het ophalen:
live_loop :opslaan do
set :foo, rrand(70, 130)
sleep 1
end
live_loop :ophalen do
puts get[:foo]
sleep 0.5
end
Het leuke aan het gebruik van get
en set
tussen meerdere threads zoals hier is dat het altijd hetzelfde resultaat oplevert iedere keer dat je op uitvoeren drukt. Vooruit, probeer het. Kijk op je het volgende in je log krijgt:
{run: 0, time: 0.0}##run: draai
└─ 125.72265625
{run: 0, time: 0.5}##run: draai
└─ 125.72265625
{run: 0, time: 1.0}##run: draai
└─ 76.26220703125
{run: 0, time: 1.5}##run: draai
└─ 76.26220703125
{run: 0, time: 2.0}##run: draai
└─ 114.93408203125
{run: 0, time: 2.5}##run: draai
└─ 114.93408203125
{run: 0, time: 3.0}##run: draai
└─ 75.6048583984375
{run: 0, time: 3.5}##run: draai
└─ 75.6048583984375
Probeer het een paar keer uit te voeren, zie je wel, het is steeds hetzelfde. Dit is wat we deterministisch gerag noemen en het is werkelijk heel belangrijk wanneer we onze muziek als code willen delen en zeker willen weten dat de persoon die code afspeelt exact hetzelfde hoort als wat we wilden dat ze hoorden (net als een MP3 afpselen of een internet stream voor alle luisteraars hezelfde klinkt).
Eerder, in sectie 5.6, bespraken we waarom variabelen gebruiken over meerdere threads voor willekeurig gedrag kan zorgen. Daardoor is het betrouwbaar reproduceren zoals de volgende code niet mogelijk:
## Een voorbeeld van niet deterministisch gedrag
## (veroorzaakt door race condities veroorzaakt door meerdere
## live lussen die dezelfde variable manipuleren
## op hetzelfde moment).
##
## Wanneer je deze code uitvoert zul je opmerken
## dat de lijst die wordt afgedrukt
## niet altijd gesorteerd is
a = (ring 6, 5, 4, 3, 2, 1)
live_loop :geschud do
a = a.shuffle
sleep 0.5
end
live_loop :gesorteerd do
a = a.sort
sleep 0.5
puts "gesorteerd: ", a
end
Laten we kijken hoe dit eruit ziet wanneer we get
en set
gebruiken:
## Een voorbeeld van deterministisch gedrag
## (ondanks gelijktijdige toegang tot gedeelde toestand)
## door het gebruik van het tijd toestand systeem van Sonic Pi.
##
## Wanneer deze code wordt uitgevoerd is de lijst
## die wordt afgedrukt altijd gesorteerd!
set :a, (ring 6, 5, 4, 3, 2, 1)
live_loop :geschud do
set :a, get[:a].shuffle
sleep 0.5
end
live_loop :gesorteerd do
set :a, get[:a].sort
sleep 0.5
puts "gesorteerd: ", get[:a]
end
Merk op dat de code bijna identiek is aan de versie die de variabele gebruikt hiervoor. Echter wanneer je de code uitvoert gedraagt het zich zoals je zou verwachten met elk typisch stuk Sonic Pi code: het doet elke keer hetzelfde in dit geval dankzij het tijd toestand systeem.
Gebruik daarom wanneer je informatie deelt tussen live lussen en threads get
en set
in plaat van variabelen voor deterministisch en reproduceerbaar gedrag.