# Потоки

Итак, вы написали чумовую бас-партию и заводной ритм. Как сыграть обе эти части одновременно? Одно из решений - переплести их вместе вручную - играть небольшую часть баса, затем немного от ударных, потом еще бас… Однако, вскоре становится очень сложно даже думать о том, как разместить это все во времени, особенно если вы начнёте добавлять новые элементы.

Что если бы Sonic Pi мог соединять партии инструментов за вас автоматически? Вообще-то это возможно, для этого вам надо использовать специальную вещь, которая называется поток выполнения.

## Бесконечные Циклы

Дабы не усложнять наш пример, представим, что это и есть крутой ритм и потрясающая бас-партия:

    loop do
      sample :drum_heavy_kick
      sleep 1
    end
    loop do
      use_synth :fm
      play 40, release: 0.2
      sleep 0.5
    end

Как мы уже обсуждали, циклы - это черные дыры в программе. Как только начинает выполняться цикл, выйти из него уже нельзя, не нажав кнопку “Остановить”. Как сыграть сразу оба цикла в одно и то же время? Надо сообщить Sonic Pi, что мы хотим выполнять что-то параллельно с остальной частью кода. Вот тут-то нам и придут на помощь потоки выполнения.

## Спасительные Потоки

    in_thread do
      loop do
        sample :drum_heavy_kick
        sleep 1
      end
    end
    loop do
      use_synth :fm
      play 40, release: 0.2
      sleep 0.5
    end

Обернув первый цикл в do/end блок типа `in_thread`, мы заставляем Sonic Pi выполнять содержимое блока do/end точно в то же самое время, когда начинается следующее выражение после блока do/end. В нашем примере таковым является второй цикл. Попробуйте, и вы услышите, как ударные и бас переплетаются вместе!

Теперь, что если мы хотим добавить синт поверх. Что-то типа:

    in_thread do
      loop do
        sample :drum_heavy_kick
        sleep 1
      end
    end
    loop do
      use_synth :fm
      play 40, release: 0.2
      sleep 0.5
    end
    loop do
      use_synth :zawa
      play 52, release: 2.5, phase: 2, amp: 0.5
      sleep 2
    end

Опять та же самая проблема. Первый цикл воспроизводится вместе со вторым из-за `in_thread`. Но третий цикл не достигается. То есть нам нужен ещё один поток:

    in_thread do
      loop do
        sample :drum_heavy_kick
        sleep 1
      end
    end
    in_thread do
      loop do
        use_synth :fm
        play 40, release: 0.2
        sleep 0.5
      end
    end
    loop do
      use_synth :zawa
      play 52, release: 2.5, phase: 2, amp: 0.5
      sleep 2
    end

## Течёт, Как Поток

Вас может это удивить, но при нажатии кнопки “Выполнить” также создаётся поток выполнения кода. Вот почему её многократное нажатие наслаивает звуки друг на друга. Запуски автоматически наслаивают звуки, потому что они сами являются потоками.

## Область Видимости

По мере овладевания секретами мастерства Sonic Pi вы узнаете, что потоки - это самые важные строительные блоки вашей музыки. Не последним их качеством является способность изолировать от других потоков то, что называется текущей установкой. Что это значит? Ну, когда вы переключаете синт при помощи `use_synth`, на самом деле вы изменяете синт в текущем потоке - ни в одном другом потоке он не изменится. Давайте посмотрим на это в действии:

    play 50
    sleep 1
    in_thread do
      use_synth :tb303
      play 50
    end
    sleep 1
    play 50

Обратите внимание, как звук в середине отличается от остальных. Команда `use_synth` применилась только к тому потоку, где она была выполнена, а не к окружающему главному потоку выполнения программы.

## Наследование

Когда вы создаёте новый поток, вызывая `in_thread`, то он автоматически наследует все текущие настройки из родительского потока. Проверим это:

    use_synth :tb303
    play 50
    sleep 1
    in_thread do
      play 55
    end

Заметили, что вторая нота воспроизводится на `:tb303`, несмотря на то, что это происходит в отдельном потоке? Любые регулировки, устанавливаемые различными `use_*` функциями, будут вести себя аналогично.

При создании, потоки наследуют все установки от своего родителя, но любые последующие изменения не имеют обратного эффекта.

## Именование Потоков

Наконец, мы можем называть наши потоки:

    in_thread(name: :bass) do
      loop do
        use_synth :prophet
        play chord(:e2, :m7).choose, release: 0.6
        sleep 0.5
      end
    end
    in_thread(name: :drums) do
      loop do
        sample :elec_snare
        sleep 1
      end
    end

Посмотрите на панель сообщений, когда этот код выполняется. Видите, как появляются сообщения, в которые включены имена потоков?

    [Run 36, Time 4.0, Thread :bass]
     |- synth :prophet, {release: 0.6, note: 47}

## Каждый Поток Со Своим Именем

Последнее, что вам нужно узнать об именованных потоках, это то, что только один поток с определённым именем может выполняться одновременно. Рассмотрим следующий код:

    in_thread do
      loop do
        sample :loop_amen
        sleep sample_duration :loop_amen
      end
    end

Скопируйте этот фрагмент в пустой буфер редактора и нажмите кнопку “Выполнить”. Нажмите её еще пару раз. Получилась какафония от того, что много повторений амен-брейка смешались вместе. Ладно, нажимайте “Остановить”.

Это то самое поведение, которое нам не раз уже доводилось наблюдать. Если нажимать кнопку “Выполнить”, то новый звук накладывается поверх уже играющего. Поэтому, если у вас есть цикл, и вы нажмёте кнопку “Выполнить” три раза, то получится три слоя циклов, звучащих вместе.

Но ситуация меняется с именованными потоками:

    in_thread(name: :amen) do
      loop do
        sample :loop_amen
        sleep sample_duration :loop_amen
      end
    end

Теперь попробуте понажимать кнопку “Выполнить” с этим кодом. Вы услышите только один цикл амен-брейк. В сообщениях вы также увидите:

    ==> Пропуск создания потока: thread, поток с именем :amen уже существует.

Sonic Pi сообщает вам, что поток с именем `:amen` уже существует, так что он не создаст ещё одного такого же.

Сейчас такое поведение может не показаться вам таким уж полезным. Но в дальнейшем вы ещё вспомните о нём, когда мы начнем лайвкодинг…