Подтвердить что ты не робот

Последствия размера стека Ruby fiber 4kB

Волокна - относительно новая концепция для меня. Я знаю, что каждый размер стека волокон ограничен 4 КБ, и я продолжаю читать, что я должен "остерегаться" этого. Каковы реальные последствия этого предела для реального мира?

Edit:

Похоже, что это ограничение 4kB не является таким препятствием в конце концов и требует большого количества локальных переменных (4045) внутри самого волокна, чтобы вызвать повышение SystemStackError.

count = 0
loop do
  count += 1
  puts count
  varlist = String.new
  count.times do |i|
    varlist += "a#{i} = 1\n"
  end
  s = "fiber = Fiber.new do \n #{varlist} \n end \n fiber.resume"
  eval(s)
end

Не самый элегантный код, но он, похоже, демонстрирует ограничения стека волокон. Кажется, что он возвращает только значения, локальные переменные (все из которых содержат ссылку на объект в куче), а вызовы методов получаются в стеке. Я не тестировал, являются ли локальные переменные и т.д. В методах, вызываемых из волокна, частью стека волокон.

Изменить 2:

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

Следующий код не выполняется на итерации 4 031 и указывает, что переменные в вызываемых методах становятся частью стека волокон:

count = 0
loop do
  count += 1
  puts count
  varlist = String.new
  count.times do |i|
    varlist += "a#{i} = 1\n"
  end
  m = "def meth\n #{varlist} \n end"
  eval(m)
  fiber = Fiber.new do
    meth
  end
  fiber.resume
end

Изменить 3:

Просто попробовал запустить исходный код на Rubinius 2.0. На его волокнах нет предела стека 4 кБ, хотя после 3500-й итерации он становится все более и менее медленным, а около 5000-й итерации он усредняет примерно одну итерацию в секунду. Я не знаю, есть ли ограничение с RBX, потому что я выхожу из исполнения только с более чем 5 100 итерациями. RBX также использует в несколько раз больше памяти, чем MRI 1.9.3.

JRuby 1.7 также не имеет размера стека 4 кБ для волокон, и если волокна имеют максимальный размер стека, он мне неизвестен. Я завершил 5000 итераций первого примера кода без проблем, хотя, как и следовало ожидать, JVM пережевывала несколько сотен МБ ОЗУ.

4b9b3361

Ответ 1

Следствием этого является то, что вы должны уделять больше внимания памяти вашего кода Fiber, поскольку у вас может быть утечка памяти.

Некоторые рекурсивные функции могут вызвать проблемы.

Ответ 2

Как Антон упомянул в своем ответе, ваш код с интенсивной памятью внутри волокна. Примеры материалов, которые могут (потенциально) съесть много памяти:

  • Большие строки (т.е. строка, содержащая HTTP-ответ приличного размера)
  • Рекурсивные функции (уровень стека слишком глубокий!)
  • Потоки или потоковые объекты: будьте ОЧЕНЬ осторожны в потоковых буферах; если они приблизятся или превысят 4k, вы начнете видеть очень странное поведение.