Ruby мьютекс против GIL - PullRequest
       1

Ruby мьютекс против GIL

2 голосов
/ 26 февраля 2020

Позволяет ли мьютекс Ruby одновременно выполнять два потока, если один поток ожидает блокировки ввода / вывода?

Это мое понимание того, как GIL работает для MRI. Мне интересно, есть ли разница между мьютексом и GIL?

Ответы [ 2 ]

3 голосов
/ 26 февраля 2020

Да, это работает. Только из-за этого использование потоков в MRI действительно полезно для многих рабочих нагрузок, хотя только один поток может одновременно выполнять «код».

Типичным примером является веб-приложение, такое как приложение Rails. Здесь вы можете запустить несколько потоков, например, с помощью Puma, в одном процессе, каждый из которых обрабатывает один запрос. Поскольку вы часто ждете базу данных здесь, может выполняться другой поток. Это работает, потому что адаптер базы данных (например, mysql2 или pg) освобождает GIL при вызове базы данных и повторно получает его, как только ответ приходит и доставляется вызывающей стороне.

С помощью Mutex, однако, вы гарантируете, что определенный блок кода выполняется только одним потоком за раз. Типичным примером является сумматор:

class Adder
  attr_reader :number

  def initialize
    @number = 0
  end

  def add(number)
    new_number = @number
    new_number = new_number + number
    @number = new_number

    # The above code is extremely verbose to show what's happening here.
    # It is equivalent to
    # @number += number
  end
end

Здесь метод Adder#add не сохраняет потоки. Если несколько потоков попытаются одновременно добавить числа, некоторые обновления будут потеряны, так как операция не атомарна c (но состоит из чтения, операции и записи). С Mutex около add вы можете убедиться, что операция завершается в одном потоке, а общие структуры данных обновляются последовательно.

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

Если вам все еще это необходимо, гем 1011 * concurrent- ruby предоставляет некоторые Потокобезопасные структуры данных, которые могут помочь с обменом данными через границы потоков.

2 голосов
/ 26 февраля 2020

Глобальная блокировка интерпретатора в реализации по умолчанию (MRI) предотвращает одновременное выполнение любых двух Ruby потоков. Mutex предотвращает одновременное выполнение потоков , указанных c, в то время как другие могут делать что угодно.

Обратите внимание, что правила отличаются в реализациях, не имеющих GIL, таких как J Ruby, где потоки могут выполняться независимо и одновременно.

По сути, глобальная блокировка интерпретатора сама по себе является мьютексом, но она задействована по умолчанию, а не явно в вашем коде, как при synchronize.

Если поток заблокирован в ожидании мьютекса, другие потоки продолжают работать нормально, они могут делать все, что им нужно независимо.

Глобальная блокировка интерпретатора также отличается тем, что ваша Ruby поток будет периодически прерываться, чтобы другие потоки могли работать. Это необходимо для предотвращения монополизации блокировки одним потоком.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...