# Параллелизм - Rubinius
Rubinius is an implementation of the Ruby programming language. The Rubinius bytecode virtual machine is written in C++. The bytecode compiler is written in pure Ruby. The vast majority of the core library is also written in Ruby, with some supporting primitives that interact with the VM directly.
Author: Less Than Three. <3. http://less.thanthree.com

1.2.3

## Параллелизм

Для обеспечения параллелизма Rubinius поддерживает те же базовые конструкции, что и MRI Ruby: `Treads` и `Fibers`. Создан также и новый API, для реализации акторов: `Actors`. Акторы обеспечивают параллелизм без участия мутексов и блокировок в передаче статуса между тредами.

Акторы выполняются параллельно, но не имеют общего статуса. Вместо этого они передают другим акторам сообщения. В качестве примера создадим два актора при помощи `Actor.spawn`: `ping` и `pong`. Пусть они обмениваются сообщениями до тех пор, пока совместно не произведут инкремент переменной до 1000:

    require 'actor'
    pong = nil
    ping = Actor.spawn do
      loop do
        count = Actor.receive
        break puts(count) if count > 1000
        pong << (count + 1)
      end
    end
    pong = Actor.spawn do
      loop do
        count = Actor.receive
        break puts(count) if count > 1000
        ping << (count + 1)
      end
    end
    ping << 1
    sleep 1

Обратите внимание: акторы принимают сообщения посредством `Actor.receive`. Этот вызов блокирует актор до тех пор, пока сообщение не придет в его «почтовый ящик». Передавая `Actor.receive` блок и используя фильтрацию сообщений, можно учитывать в алгоритме тип сообщения:

    Actor.receive do |filter|
      filter.when(Ready) do |who|
        # SNIP
      end
      filter.when(Work) do |work|
        ready_workers.pop << work
      end
      filter.when(Actor::DeadActorError) do |exit|
        print "Actor exited with message: #{exit.reason}\n"
        ready_workers << Actor.spawn_link(&work_loop)
      end
    end

Фильтры применяют к сообщениям метод `===`, поэтому `when()` можно передавать, например, регулярные выражения, классы или процедуры — в зависимости от конкретной ситуации.

Акторы могут приобретать отношения «предок-потомок» посредством `Actor.spawn_link`. Если потомок по какой-то причине «умирает», актор-родитель может получить об этом извещение, если перед запуском потомка переменная `Actor.trap_exit` была установлена в `true`. Создадим актор-супервизор, управляющий некоторой очередью при помощи 10 акторов-работников, выполняющих непосредственный процессинг очереди. Если работник умирает (т.е. инициирует исключение), супервизор получает сообщение `Actor::DeadActorError`.

    require 'actor'

    Ready = Struct.new(:this)
    Work = Struct.new(:msg)

    @supervisor = Actor.spawn do
      supervisor = Actor.current
      work_loop = Proc.new do
        loop do
          work = Actor.receive
          puts("Processing: #{work.msg}")
          supervisor << Ready[Actor.current]
        end
      end

      Actor.trap_exit = true
      ready_workers = []
      10.times do |x|
        # start 10 worker actors
        ready_workers << Actor.spawn_link(&work_loop)
      end
      loop do
        Actor.receive do |f|
          f.when(Ready) do |who|
            # SNIP
          end
          f.when(Work) do |work|
            ready_workers.pop << work
          end
          f.when(Actor::DeadActorError) do |exit|
            print "Actor exited with message: #{exit.reason}\n"
            ready_workers << Actor.spawn_link(&work_loop)
          end
        end
      end
    end

    10.times do |idx|
      @supervisor << Work[idx]
    end
    sleep 1

Приведенный пример — фрагмент кода из «girl_friday». Если у Вас возникли вопросы, поизучайте этот проект.