10.1 Set и Get

# Set и Get

Sonic PI имеет глобальное хранилище памяти, называемое Временным состоянием. В основном оно используется чтобы "установить" (set) информацию и "получить" (get)  информацию. Давайте нырнем глубже...

## Set

Чтобы хранить информацию во Временном Состоянии нам нужны две вещи:

1. информация, которую мы хотим сохранить,
2. уникальное имя (ключ) для этой информации.

Например, мы можем захотеть сохранить число `3000` с ключом `:intensity`. Это можно сделать используя функцию  `set`:

```
set :intensity, 3000
```

Мы можем дать ключу любое имя. Если какая-то информация уже хранится под этим именем, наш новый `set` перезапишет её:

```
set :intensity, 1000
set :intensity, 3000
```

В примере выше, где мы сохранили оба числа под одним ключом, последний вызов `set` 'побеждает', поэтому число связанное с `:intensity` будет равно `3000`, так как первый вызов 'set'  эффективно перезаписан.

## Get

Для извлечения информации из Временного Состояния нам просто нужен ключ, который мы использовали в `set`, в нашем случае это `:intensity`. Тогда нам просто нужно вызвать `get[:intensity]`, результат которого выведем на экран:

```
print get[:intensity] #=> выведет 3000
```

Обратите внимание, что запросы `get` могут возвращать информацию, которая была записана в `set` в предыдущем запуске исполнения кода. После того, как часть информации была записана в `set`, она становится доступной до тех пор, пока она либо не будет переопределена (точно так же, как мы переопределили значение`:intensity` от `1000` к ` 3000`), либо Sonic Pi не будет закрыт.

## Множество потоков выполнения

Основное преимущество системы Time State заключается в том, что ее можно безопасно использовать в потоках или в живых циклах. Например, у вас может быть сделана установка для одного живого цикла, а другой может ее получить:

```
live_loop :setter do
  set :foo, rrand(70, 130)
  sleep 1
end
live_loop :getter do
  puts get[:foo]
  sleep 0.5
end
```

Хорошая вещь об использовании `get` и` set` в потоках, подобных этому, заключается в том, что всегда будет выдаваться один и тот же результат всякий раз, когда вы запускаете исполнение кода. Попробуйте этом, и посмотрите, есть ли в вашем журнале следующее:

```
{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
```

Попробуйте запустить этот код несколько раз - видите,  результат одинаков каждый раз. Это то, что мы называем детерминированным поведением, и это действительно очень важно, когда мы хотим поделиться своей музыкой в виде кода и знать, что человек, играющий код, слышит именно то, что мы хотели, чтобы он услышал (точно так же, как воспроизведение MP3 или интернет-стрим звучат одинаково для всех слушателей).

## Просто о системе детерминированных состояний

В разделе 5.6 мы обсуждали, почему использование переменных в потоках может привести к случайному поведению. Это лишает нас возможности надежно воспроизводить код, такой как этот:

```
## Пример недетерминированного поведения
## (из-за гонки состояний, вызванной несколькими
## живыми циклами, манипулирующими одной и той же переменной
## в одно и то же время).
##
## Если вы запустите этот код, вы заметите
## что список, отображаемый в  журнале
## не всегда сортируется!
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
```

Давайте посмотрим, как это может выглядеть, используя `get` и` set`:

```
## Пример детерминированного поведения
## (несмотря на одновременный доступ к общему состоянию)
## используя новую систему Time State от Sonic Pi.
##
## Когда этот код выполняется, список,
## отображаемый в журнале, всегда отсортирован!
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
```

Обратите внимание, что этот код в значительной степени идентичен версии, использующей переменную. Однако когда вы запускаете код, он ведет себя так, как вы ожидаете с любым типичным кодом Sonic Pi - * он делает то же самое каждый раз * в этом случае благодаря системе Time State.

Поэтому, когда вы делитесь информацией между живыми циклами и потоками, используйте `get` и` set` вместо переменных для детерминированного, воспроизводимого поведения.
