💡 Инструкция: Выберите один ответ из пяти. Время — 85 минут. У каждого задания ровно один правильный вариант. Фрагменты рассчитаны на Ruby 4.0.6; задания Rails — на Rails 8.1.3. После завершения откроются общий процент, 6 тематических результатов и разбор всех ответов.
Вопрос 1 из 30
Как изменится состояние программы после выполнения кода по теме «Планирование»? Одного совпавшего вывода недостаточно — проверьте также вторую часть ответа.
Ruby Ruby — Планирование Копировать
# Проследите выполнение и выберите точный результат.
started = Process.clock_gettime(Process::CLOCK_MONOTONIC)
threads = 2.times.map { Thread.new { sleep 0.1 } }
threads.each(&:join)
elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - started
p elapsed
Два `sleep` выполняются конкурентно и общее время близко к одному ожиданию, а не сумме. Это объясняется тем, что изменение общего объекта несколькими потоками требует синхронизации на уровне составной операции, даже если отдельные методы выглядят простыми.
Два `sleep` выполняются конкурентно и общее время близко к одному ожиданию, а не сумме. Это объясняется тем, что Ruby-потоки планируются VM и ОС; в CRuby GVL ограничивает параллельное выполнение Ruby-кода, но ожидание ввода-вывода может перекрываться.
Барьер заставляет потоки прочитать исходное состояние до записи и делает lost update воспроизводимым. Это объясняется тем, что Ruby-потоки планируются VM и ОС; в CRuby GVL ограничивает параллельное выполнение Ruby-кода, но ожидание ввода-вывода может перекрываться.
Два `sleep` выполняются конкурентно и общее время близко к одному ожиданию, а не сумме. Это объясняется тем, что конкурентный тест должен проверять инвариант на множестве чередований; один удачный запуск не доказывает отсутствие гонки.
Queue безопасно передаёт значение от producer к consumer и блокирует `pop` до появления элемента. Это объясняется тем, что Ruby-потоки планируются VM и ОС; в CRuby GVL ограничивает параллельное выполнение Ruby-кода, но ожидание ввода-вывода может перекрываться.
Вопрос 2 из 30
Как изменится состояние программы после выполнения кода по теме «Общий доступ»? Одного совпавшего вывода недостаточно — проверьте также вторую часть ответа.
Ruby Ruby — Общий доступ Копировать
# Проследите выполнение и выберите точный результат.
count = 0
lock = Mutex.new
threads = 4.times.map do
Thread.new { 1_000.times { lock.synchronize { count += 1 } } }
end
threads.each(&:join)
p count
Mutex делает чтение, увеличение и запись счётчика одной критической секцией и сохраняет ожидаемое итоговое число. Причина такого результата: изменение общего объекта несколькими потоками требует синхронизации на уровне составной операции, даже если отдельные методы выглядят простыми.
Замороженная строка передаётся как shareable-объект, а `worker.value` дожидается завершения Ractor и возвращает строку `READY`. Причина такого результата: изменение общего объекта несколькими потоками требует синхронизации на уровне составной операции, даже если отдельные методы выглядят простыми.
Барьер заставляет потоки прочитать исходное состояние до записи и делает lost update воспроизводимым. Причина такого результата: изменение общего объекта несколькими потоками требует синхронизации на уровне составной операции, даже если отдельные методы выглядят простыми.
Mutex делает чтение, увеличение и запись счётчика одной критической секцией и сохраняет ожидаемое итоговое число. Причина такого результата: Ruby-потоки планируются VM и ОС; в CRuby GVL ограничивает параллельное выполнение Ruby-кода, но ожидание ввода-вывода может перекрываться.
Mutex делает чтение, увеличение и запись счётчика одной критической секцией и сохраняет ожидаемое итоговое число. Причина такого результата: conditionVariable, Queue и SizedQueue координируют порядок; ожидание должно проверять условие в цикле, а не считать одно пробуждение доказательством готовности.
Вопрос 3 из 30
Какой вариант верно описывает состояние объектов после выполнения кода «Изоляция»? Выберите связку, в которой верны и основной вывод, и его обоснование.
Ruby Ruby — Изоляция Копировать
# Проследите выполнение и выберите точный результат.
message = 'ready'.freeze
worker = Ractor.new(message) { |value| value.upcase }
p worker.value
Замороженная строка передаётся как shareable-объект, а `worker.value` дожидается завершения Ractor и возвращает строку `READY`. Такой итог следует из правила: `Thread#join` и `Thread#value` оба ждут завершения потока и повторно поднимают его необработанное исключение у ожидающего кода; `value` дополнительно возвращает результат успешного потока.
Вызов `worker.value` повторно поднимает `RuntimeError` из рабочего потока; внешний `rescue` получает класс ошибки и сообщение `boom`. Такой итог следует из правила: в Ruby 4 shareable-объекты передаются между Ractor по ссылке, неразделяемые значения при обычной отправке глубоко копируются, а `move: true` передаёт владение и закрывает доступ отправителю.
Замороженная строка передаётся как shareable-объект, а `worker.value` дожидается завершения Ractor и возвращает строку `READY`. Такой итог следует из правила: conditionVariable, Queue и SizedQueue координируют порядок; ожидание должно проверять условие в цикле, а не считать одно пробуждение доказательством готовности.
Замороженная строка передаётся как shareable-объект, а `worker.value` дожидается завершения Ractor и возвращает строку `READY`. Такой итог следует из правила: в Ruby 4 shareable-объекты передаются между Ractor по ссылке, неразделяемые значения при обычной отправке глубоко копируются, а `move: true` передаёт владение и закрывает доступ отправителю.
Mutex делает чтение, увеличение и запись счётчика одной критической секцией и сохраняет ожидаемое итоговое число. Такой итог следует из правила: в Ruby 4 shareable-объекты передаются между Ractor по ссылке, неразделяемые значения при обычной отправке глубоко копируются, а `move: true` передаёт владение и закрывает доступ отправителю.
Вопрос 4 из 30
Какой вариант верно описывает состояние объектов после выполнения кода «Синхронизация»? Верный вариант не содержит частично правильной подмены причины или следствия.
Ruby Ruby — Синхронизация Копировать
# Проследите выполнение и выберите точный результат.
queue = Queue.new
producer = Thread.new { queue << :task }
consumer = Thread.new { p queue.pop }
[producer, consumer].each(&:join)
Барьер заставляет потоки прочитать исходное состояние до записи и делает lost update воспроизводимым. Механизм результата таков: conditionVariable, Queue и SizedQueue координируют порядок; ожидание должно проверять условие в цикле, а не считать одно пробуждение доказательством готовности.
Queue безопасно передаёт значение от producer к consumer и блокирует `pop` до появления элемента. Механизм результата таков: Ruby-потоки планируются VM и ОС; в CRuby GVL ограничивает параллельное выполнение Ruby-кода, но ожидание ввода-вывода может перекрываться.
Queue безопасно передаёт значение от producer к consumer и блокирует `pop` до появления элемента. Механизм результата таков: conditionVariable, Queue и SizedQueue координируют порядок; ожидание должно проверять условие в цикле, а не считать одно пробуждение доказательством готовности.
Два `sleep` выполняются конкурентно и общее время близко к одному ожиданию, а не сумме. Механизм результата таков: conditionVariable, Queue и SizedQueue координируют порядок; ожидание должно проверять условие в цикле, а не считать одно пробуждение доказательством готовности.
Queue безопасно передаёт значение от producer к consumer и блокирует `pop` до появления элемента. Механизм результата таков: изменение общего объекта несколькими потоками требует синхронизации на уровне составной операции, даже если отдельные методы выглядят простыми.
Вопрос 8 из 30
Почему успешный пример ещё не доказывает надёжность решения «Общий доступ»? Верный вариант не содержит частично правильной подмены причины или следствия.
Ruby Ruby — Общий доступ Копировать
# Обычный запуск проходит. Найдите скрытый риск.
count = 0
lock = Mutex.new
threads = 4.times.map do
Thread.new { 1_000.times { lock.synchronize { count += 1 } } }
end
threads.each(&:join)
p count
Добавление случайного sleep иногда проявляет дефект, но создаёт нестабильный тест без гарантии нужного порядка. Этот риск связан с тем, что изменение общего объекта несколькими потоками требует синхронизации на уровне составной операции, даже если отдельные методы выглядят простыми.
Надежда на GVL не является контрактом атомарности: переключение возможно между операциями и реализация Ruby может отличаться. Этот риск связан с тем, что изменение общего объекта несколькими потоками требует синхронизации на уровне составной операции, даже если отдельные методы выглядят простыми.
Вывод о пользе потоков для вычислений по результату I/O-теста неверен: CPU-нагрузка под GVL ведёт себя иначе. Этот риск связан с тем, что изменение общего объекта несколькими потоками требует синхронизации на уровне составной операции, даже если отдельные методы выглядят простыми.
Надежда на GVL не является контрактом атомарности: переключение возможно между операциями и реализация Ruby может отличаться. Этот риск связан с тем, что Ruby-потоки планируются VM и ОС; в CRuby GVL ограничивает параллельное выполнение Ruby-кода, но ожидание ввода-вывода может перекрываться.
Надежда на GVL не является контрактом атомарности: переключение возможно между операциями и реализация Ruby может отличаться. Этот риск связан с тем, что conditionVariable, Queue и SizedQueue координируют порядок; ожидание должно проверять условие в цикле, а не считать одно пробуждение доказательством готовности.
Вопрос 9 из 30
Что может сломаться при переносе этого решения «Изоляция» в рабочую систему? Смотрите на всю причинную связку, а не только на знакомую формулировку.
Ruby Ruby — Изоляция Копировать
# Обычный запуск проходит. Найдите скрытый риск.
message = 'ready'.freeze
worker = Ractor.new(message) { |value| value.upcase }
p worker.value
Обычная отправка большого изменяемого графа запускает глубокое копирование; это дорого, а объект, который нельзя скопировать, приводит к `TypeError`. Уязвимое место возникает потому, что в Ruby 4 shareable-объекты передаются между Ractor по ссылке, неразделяемые значения при обычной отправке глубоко копируются, а `move: true` передаёт владение и закрывает доступ отправителю.
Обычная отправка большого изменяемого графа запускает глубокое копирование; это дорого, а объект, который нельзя скопировать, приводит к `TypeError`. Уязвимое место возникает потому, что `Thread#join` и `Thread#value` оба ждут завершения потока и повторно поднимают его необработанное исключение у ожидающего кода; `value` дополнительно возвращает результат успешного потока.
Обычная отправка большого изменяемого графа запускает глубокое копирование; это дорого, а объект, который нельзя скопировать, приводит к `TypeError`. Уязвимое место возникает потому, что conditionVariable, Queue и SizedQueue координируют порядок; ожидание должно проверять условие в цикле, а не считать одно пробуждение доказательством готовности.
Если поток запущен, но его результат нигде не ожидают, отказ может остаться только в диагностическом выводе и не изменить итог основной операции, хотя часть работы потеряна. Уязвимое место возникает потому, что в Ruby 4 shareable-объекты передаются между Ractor по ссылке, неразделяемые значения при обычной отправке глубоко копируются, а `move: true` передаёт владение и закрывает доступ отправителю.
Надежда на GVL не является контрактом атомарности: переключение возможно между операциями и реализация Ruby может отличаться. Уязвимое место возникает потому, что в Ruby 4 shareable-объекты передаются между Ractor по ссылке, неразделяемые значения при обычной отправке глубоко копируются, а `move: true` передаёт владение и закрывает доступ отправителю.
Вопрос 10 из 30
Какой рабочий сбой вероятнее всего связан именно с механизмом «Синхронизация»? Верный вариант не содержит частично правильной подмены причины или следствия.
Ruby Ruby — Синхронизация Копировать
# Обычный запуск проходит. Найдите скрытый риск.
queue = Queue.new
producer = Thread.new { queue << :task }
consumer = Thread.new { p queue.pop }
[producer, consumer].each(&:join)
Самодельное ожидание на флаге с `sleep` создаёт гонку, лишнюю задержку и нагрузку при пустой очереди. К такому сбою приводит правило: изменение общего объекта несколькими потоками требует синхронизации на уровне составной операции, даже если отдельные методы выглядят простыми.
Вывод о пользе потоков для вычислений по результату I/O-теста неверен: CPU-нагрузка под GVL ведёт себя иначе. К такому сбою приводит правило: conditionVariable, Queue и SizedQueue координируют порядок; ожидание должно проверять условие в цикле, а не считать одно пробуждение доказательством готовности.
Самодельное ожидание на флаге с `sleep` создаёт гонку, лишнюю задержку и нагрузку при пустой очереди. К такому сбою приводит правило: conditionVariable, Queue и SizedQueue координируют порядок; ожидание должно проверять условие в цикле, а не считать одно пробуждение доказательством готовности.
Добавление случайного sleep иногда проявляет дефект, но создаёт нестабильный тест без гарантии нужного порядка. К такому сбою приводит правило: conditionVariable, Queue и SizedQueue координируют порядок; ожидание должно проверять условие в цикле, а не считать одно пробуждение доказательством готовности.
Самодельное ожидание на флаге с `sleep` создаёт гонку, лишнюю задержку и нагрузку при пустой очереди. К такому сбою приводит правило: Ruby-потоки планируются VM и ОС; в CRuby GVL ограничивает параллельное выполнение Ruby-кода, но ожидание ввода-вывода может перекрываться.
Вопрос 12 из 30
Какой дефект может проявиться на границе показанного сценария «Устойчивость к сбоям»? Смотрите на всю причинную связку, а не только на знакомую формулировку.
Ruby Ruby — Устойчивость к сбоям Копировать
# Обычный запуск проходит. Найдите скрытый риск.
worker = Thread.new { raise 'boom' }
begin
worker.value
rescue => e
p [e.class, e.message]
end
Обычная отправка большого изменяемого графа запускает глубокое копирование; это дорого, а объект, который нельзя скопировать, приводит к `TypeError`. Проблема возникает из-за того, что `Thread#join` и `Thread#value` оба ждут завершения потока и повторно поднимают его необработанное исключение у ожидающего кода; `value` дополнительно возвращает результат успешного потока.
Если поток запущен, но его результат нигде не ожидают, отказ может остаться только в диагностическом выводе и не изменить итог основной операции, хотя часть работы потеряна. Проблема возникает из-за того, что `Thread#join` и `Thread#value` оба ждут завершения потока и повторно поднимают его необработанное исключение у ожидающего кода; `value` дополнительно возвращает результат успешного потока.
Если поток запущен, но его результат нигде не ожидают, отказ может остаться только в диагностическом выводе и не изменить итог основной операции, хотя часть работы потеряна. Проблема возникает из-за того, что conditionVariable, Queue и SizedQueue координируют порядок; ожидание должно проверять условие в цикле, а не считать одно пробуждение доказательством готовности.
Надежда на GVL не является контрактом атомарности: переключение возможно между операциями и реализация Ruby может отличаться. Проблема возникает из-за того, что `Thread#join` и `Thread#value` оба ждут завершения потока и повторно поднимают его необработанное исключение у ожидающего кода; `value` дополнительно возвращает результат успешного потока.
Если поток запущен, но его результат нигде не ожидают, отказ может остаться только в диагностическом выводе и не изменить итог основной операции, хотя часть работы потеряна. Проблема возникает из-за того, что в Ruby 4 shareable-объекты передаются между Ractor по ссылке, неразделяемые значения при обычной отправке глубоко копируются, а `move: true` передаёт владение и закрывает доступ отправителю.
Вопрос 14 из 30
Какое свойство Ruby или Rails определяет результат примера «Общий доступ»? Проверьте обе половины ответа: частично верный вариант остаётся неверным.
ConditionVariable, Queue и SizedQueue координируют порядок; ожидание должно проверять условие в цикле, а не считать одно пробуждение доказательством готовности. Из этого следует, что mutex делает чтение, увеличение и запись счётчика одной критической секцией и сохраняет ожидаемое итоговое число.
Ruby-потоки планируются VM и ОС; в CRuby GVL ограничивает параллельное выполнение Ruby-кода, но ожидание ввода-вывода может перекрываться. Из этого следует, что mutex делает чтение, увеличение и запись счётчика одной критической секцией и сохраняет ожидаемое итоговое число.
Изменение общего объекта несколькими потоками требует синхронизации на уровне составной операции, даже если отдельные методы выглядят простыми. Из этого следует, что барьер заставляет потоки прочитать исходное состояние до записи и делает lost update воспроизводимым.
Изменение общего объекта несколькими потоками требует синхронизации на уровне составной операции, даже если отдельные методы выглядят простыми. Из этого следует, что замороженная строка передаётся как shareable-объект, а `worker.value` дожидается завершения Ractor и возвращает строку `READY`.
Изменение общего объекта несколькими потоками требует синхронизации на уровне составной операции, даже если отдельные методы выглядят простыми. Из этого следует, что mutex делает чтение, увеличение и запись счётчика одной критической секцией и сохраняет ожидаемое итоговое число.
Вопрос 15 из 30
Какое правило Ruby или Rails объясняет поведение в теме «Изоляция»? Сопоставьте не только итог, но и правило, риск или проверку, которые с ним связаны.
В Ruby 4 shareable-объекты передаются между Ractor по ссылке, неразделяемые значения при обычной отправке глубоко копируются, а `move: true` передаёт владение и закрывает доступ отправителю. Наблюдаемое следствие: вызов `worker.value` повторно поднимает `RuntimeError` из рабочего потока; внешний `rescue` получает класс ошибки и сообщение `boom`.
ConditionVariable, Queue и SizedQueue координируют порядок; ожидание должно проверять условие в цикле, а не считать одно пробуждение доказательством готовности. Наблюдаемое следствие: замороженная строка передаётся как shareable-объект, а `worker.value` дожидается завершения Ractor и возвращает строку `READY`.
В Ruby 4 shareable-объекты передаются между Ractor по ссылке, неразделяемые значения при обычной отправке глубоко копируются, а `move: true` передаёт владение и закрывает доступ отправителю. Наблюдаемое следствие: замороженная строка передаётся как shareable-объект, а `worker.value` дожидается завершения Ractor и возвращает строку `READY`.
В Ruby 4 shareable-объекты передаются между Ractor по ссылке, неразделяемые значения при обычной отправке глубоко копируются, а `move: true` передаёт владение и закрывает доступ отправителю. Наблюдаемое следствие: mutex делает чтение, увеличение и запись счётчика одной критической секцией и сохраняет ожидаемое итоговое число.
`Thread#join` и `Thread#value` оба ждут завершения потока и повторно поднимают его необработанное исключение у ожидающего кода; `value` дополнительно возвращает результат успешного потока. Наблюдаемое следствие: замороженная строка передаётся как shareable-объект, а `worker.value` дожидается завершения Ractor и возвращает строку `READY`.
Вопрос 16 из 30
Как сформулировать правило блока «Синхронизация» без лишних обещаний? Сопоставьте не только итог, но и правило, риск или проверку, которые с ним связаны.
ConditionVariable, Queue и SizedQueue координируют порядок; ожидание должно проверять условие в цикле, а не считать одно пробуждение доказательством готовности. Именно поэтому два `sleep` выполняются конкурентно и общее время близко к одному ожиданию, а не сумме.
Изменение общего объекта несколькими потоками требует синхронизации на уровне составной операции, даже если отдельные методы выглядят простыми. Именно поэтому queue безопасно передаёт значение от producer к consumer и блокирует `pop` до появления элемента.
Ruby-потоки планируются VM и ОС; в CRuby GVL ограничивает параллельное выполнение Ruby-кода, но ожидание ввода-вывода может перекрываться. Именно поэтому queue безопасно передаёт значение от producer к consumer и блокирует `pop` до появления элемента.
ConditionVariable, Queue и SizedQueue координируют порядок; ожидание должно проверять условие в цикле, а не считать одно пробуждение доказательством готовности. Именно поэтому queue безопасно передаёт значение от producer к consumer и блокирует `pop` до появления элемента.
ConditionVariable, Queue и SizedQueue координируют порядок; ожидание должно проверять условие в цикле, а не считать одно пробуждение доказательством готовности. Именно поэтому барьер заставляет потоки прочитать исходное состояние до записи и делает lost update воспроизводимым.
Вопрос 19 из 30
Какой вариант правки выдержит граничный сценарий темы «Планирование»? Сопоставьте не только итог, но и правило, риск или проверку, которые с ним связаны.
Ruby Ruby — Планирование Копировать
# Выберите изменение, которое исправляет причину.
started = Process.clock_gettime(Process::CLOCK_MONOTONIC)
threads = 2.times.map { Thread.new { sleep 0.1 } }
threads.each(&:join)
elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - started
p elapsed
Классифицировать нагрузку как I/O или CPU и измерять на целевой VM; для CPU рассматривать процессы, Ractor или нативный код. Так закрывается риск: самодельное ожидание на флаге с `sleep` создаёт гонку, лишнюю задержку и нагрузку при пустой очереди.
Классифицировать нагрузку как I/O или CPU и измерять на целевой VM; для CPU рассматривать процессы, Ractor или нативный код. Так закрывается риск: вывод о пользе потоков для вычислений по результату I/O-теста неверен: CPU-нагрузка под GVL ведёт себя иначе.
Использовать готовую потокобезопасную очередь и определить сигнал завершения, ограничение ёмкости и реакцию на переполнение. Так закрывается риск: вывод о пользе потоков для вычислений по результату I/O-теста неверен: CPU-нагрузка под GVL ведёт себя иначе.
Классифицировать нагрузку как I/O или CPU и измерять на целевой VM; для CPU рассматривать процессы, Ractor или нативный код. Так закрывается риск: добавление случайного sleep иногда проявляет дефект, но создаёт нестабильный тест без гарантии нужного порядка.
Управлять точками синхронизации детерминированно и проверять конечный инвариант, повторяя сценарий на разных реализациях Ruby. Так закрывается риск: вывод о пользе потоков для вычислений по результату I/O-теста неверен: CPU-нагрузка под GVL ведёт себя иначе.
Вопрос 20 из 30
Какое исправление уменьшает риск, не скрывая исходное поведение «Общий доступ»? Сопоставьте не только итог, но и правило, риск или проверку, которые с ним связаны.
Ruby Ruby — Общий доступ Копировать
# Выберите изменение, которое исправляет причину.
count = 0
lock = Mutex.new
threads = 4.times.map do
Thread.new { 1_000.times { lock.synchronize { count += 1 } } }
end
threads.each(&:join)
p count
Использовать готовую потокобезопасную очередь и определить сигнал завершения, ограничение ёмкости и реакцию на переполнение. Это изменение устраняет проблему: надежда на GVL не является контрактом атомарности: переключение возможно между операциями и реализация Ruby может отличаться.
Классифицировать нагрузку как I/O или CPU и измерять на целевой VM; для CPU рассматривать процессы, Ractor или нативный код. Это изменение устраняет проблему: надежда на GVL не является контрактом атомарности: переключение возможно между операциями и реализация Ruby может отличаться.
Уменьшать совместное изменяемое состояние, использовать Queue/actor-подход или защищать весь инвариант одним механизмом. Это изменение устраняет проблему: добавление случайного sleep иногда проявляет дефект, но создаёт нестабильный тест без гарантии нужного порядка.
Уменьшать совместное изменяемое состояние, использовать Queue/actor-подход или защищать весь инвариант одним механизмом. Это изменение устраняет проблему: надежда на GVL не является контрактом атомарности: переключение возможно между операциями и реализация Ruby может отличаться.
Уменьшать совместное изменяемое состояние, использовать Queue/actor-подход или защищать весь инвариант одним механизмом. Это изменение устраняет проблему: вывод о пользе потоков для вычислений по результату I/O-теста неверен: CPU-нагрузка под GVL ведёт себя иначе.
Вопрос 21 из 30
Какой рефакторинг делает контракт блока «Изоляция» явным и проверяемым? Сопоставьте не только итог, но и правило, риск или проверку, которые с ним связаны.
Ruby Ruby — Изоляция Копировать
# Выберите изменение, которое исправляет причину.
message = 'ready'.freeze
worker = Ractor.new(message) { |value| value.upcase }
p worker.value
Передавать небольшие shareable-сообщения, проверять весь граф через `Ractor.shareable?`, измерять цену копирования и применять `move: true` лишь при явной смене владельца. Такая правка нужна из-за риска: если поток запущен, но его результат нигде не ожидают, отказ может остаться только в диагностическом выводе и не изменить итог основной операции, хотя часть работы потеряна.
Передавать небольшие shareable-сообщения, проверять весь граф через `Ractor.shareable?`, измерять цену копирования и применять `move: true` лишь при явной смене владельца. Такая правка нужна из-за риска: надежда на GVL не является контрактом атомарности: переключение возможно между операциями и реализация Ruby может отличаться.
Хранить дескрипторы потоков, явно ждать их через `value` или `join`, собирать ошибки в одном месте и отменять связанную работу при критичном отказе. Такая правка нужна из-за риска: обычная отправка большого изменяемого графа запускает глубокое копирование; это дорого, а объект, который нельзя скопировать, приводит к `TypeError`.
Передавать небольшие shareable-сообщения, проверять весь граф через `Ractor.shareable?`, измерять цену копирования и применять `move: true` лишь при явной смене владельца. Такая правка нужна из-за риска: обычная отправка большого изменяемого графа запускает глубокое копирование; это дорого, а объект, который нельзя скопировать, приводит к `TypeError`.
Управлять точками синхронизации детерминированно и проверять конечный инвариант, повторяя сценарий на разных реализациях Ruby. Такая правка нужна из-за риска: обычная отправка большого изменяемого графа запускает глубокое копирование; это дорого, а объект, который нельзя скопировать, приводит к `TypeError`.
Вопрос 22 из 30
Какой вариант правки выдержит граничный сценарий темы «Синхронизация»? Нужен вариант без логического разрыва между первой и второй частью.
Ruby Ruby — Синхронизация Копировать
# Выберите изменение, которое исправляет причину.
queue = Queue.new
producer = Thread.new { queue << :task }
consumer = Thread.new { p queue.pop }
[producer, consumer].each(&:join)
Управлять точками синхронизации детерминированно и проверять конечный инвариант, повторяя сценарий на разных реализациях Ruby. Решение адресует следующий дефект: самодельное ожидание на флаге с `sleep` создаёт гонку, лишнюю задержку и нагрузку при пустой очереди.
Использовать готовую потокобезопасную очередь и определить сигнал завершения, ограничение ёмкости и реакцию на переполнение. Решение адресует следующий дефект: добавление случайного sleep иногда проявляет дефект, но создаёт нестабильный тест без гарантии нужного порядка.
Использовать готовую потокобезопасную очередь и определить сигнал завершения, ограничение ёмкости и реакцию на переполнение. Решение адресует следующий дефект: самодельное ожидание на флаге с `sleep` создаёт гонку, лишнюю задержку и нагрузку при пустой очереди.
Классифицировать нагрузку как I/O или CPU и измерять на целевой VM; для CPU рассматривать процессы, Ractor или нативный код. Решение адресует следующий дефект: самодельное ожидание на флаге с `sleep` создаёт гонку, лишнюю задержку и нагрузку при пустой очереди.
Использовать готовую потокобезопасную очередь и определить сигнал завершения, ограничение ёмкости и реакцию на переполнение. Решение адресует следующий дефект: вывод о пользе потоков для вычислений по результату I/O-теста неверен: CPU-нагрузка под GVL ведёт себя иначе.
Вопрос 23 из 30
Какой рефакторинг делает контракт блока «Проверка корректности» явным и проверяемым? Оценивайте ответ целиком: обе части утверждения должны быть точными.
Ruby Ruby — Проверка корректности Копировать
# Выберите изменение, которое исправляет причину.
ready = Queue.new
release = Queue.new
values = []
2.times.map do
Thread.new do
snapshot = values.length
ready << true
release.pop
values << snapshot
end
end.tap do |threads|
2.times { ready.pop }
2.times { release << true }
threads.each(&:join)
end
p values
Классифицировать нагрузку как I/O или CPU и измерять на целевой VM; для CPU рассматривать процессы, Ractor или нативный код. Именно эта мера закрывает риск: добавление случайного sleep иногда проявляет дефект, но создаёт нестабильный тест без гарантии нужного порядка.
Управлять точками синхронизации детерминированно и проверять конечный инвариант, повторяя сценарий на разных реализациях Ruby. Именно эта мера закрывает риск: самодельное ожидание на флаге с `sleep` создаёт гонку, лишнюю задержку и нагрузку при пустой очереди.
Управлять точками синхронизации детерминированно и проверять конечный инвариант, повторяя сценарий на разных реализациях Ruby. Именно эта мера закрывает риск: добавление случайного sleep иногда проявляет дефект, но создаёт нестабильный тест без гарантии нужного порядка.
Использовать готовую потокобезопасную очередь и определить сигнал завершения, ограничение ёмкости и реакцию на переполнение. Именно эта мера закрывает риск: добавление случайного sleep иногда проявляет дефект, но создаёт нестабильный тест без гарантии нужного порядка.
Управлять точками синхронизации детерминированно и проверять конечный инвариант, повторяя сценарий на разных реализациях Ruby. Именно эта мера закрывает риск: вывод о пользе потоков для вычислений по результату I/O-теста неверен: CPU-нагрузка под GVL ведёт себя иначе.
Вопрос 24 из 30
Что следует изменить в решении «Устойчивость к сбоям», чтобы закрыть исходный риск? Смотрите на всю причинную связку, а не только на знакомую формулировку.
Ruby Ruby — Устойчивость к сбоям Копировать
# Выберите изменение, которое исправляет причину.
worker = Thread.new { raise 'boom' }
begin
worker.value
rescue => e
p [e.class, e.message]
end
Хранить дескрипторы потоков, явно ждать их через `value` или `join`, собирать ошибки в одном месте и отменять связанную работу при критичном отказе. После изменения не должен сохраняться риск: если поток запущен, но его результат нигде не ожидают, отказ может остаться только в диагностическом выводе и не изменить итог основной операции, хотя часть работы потеряна.
Передавать небольшие shareable-сообщения, проверять весь граф через `Ractor.shareable?`, измерять цену копирования и применять `move: true` лишь при явной смене владельца. После изменения не должен сохраняться риск: если поток запущен, но его результат нигде не ожидают, отказ может остаться только в диагностическом выводе и не изменить итог основной операции, хотя часть работы потеряна.
Хранить дескрипторы потоков, явно ждать их через `value` или `join`, собирать ошибки в одном месте и отменять связанную работу при критичном отказе. После изменения не должен сохраняться риск: обычная отправка большого изменяемого графа запускает глубокое копирование; это дорого, а объект, который нельзя скопировать, приводит к `TypeError`.
Управлять точками синхронизации детерминированно и проверять конечный инвариант, повторяя сценарий на разных реализациях Ruby. После изменения не должен сохраняться риск: если поток запущен, но его результат нигде не ожидают, отказ может остаться только в диагностическом выводе и не изменить итог основной операции, хотя часть работы потеряна.
Хранить дескрипторы потоков, явно ждать их через `value` или `join`, собирать ошибки в одном месте и отменять связанную работу при критичном отказе. После изменения не должен сохраняться риск: надежда на GVL не является контрактом атомарности: переключение возможно между операциями и реализация Ruby может отличаться.
Вопрос 27 из 30
Какой контрпример проверит реальную границу механизма «Изоляция»? Оценивайте ответ целиком: обе части утверждения должны быть точными.
Оставить внутри замороженного хеша изменяемую строку и проверить `Ractor.shareable?`: `false` покажет, что для передачи по ссылке нужна глубокая неизменяемость всего графа. Проверка относится к изменению: управлять точками синхронизации детерминированно и проверять конечный инвариант, повторяя сценарий на разных реализациях Ruby.
Проверить размер пула относительно соединений БД и внешних лимитов: больше потоков может только увеличить очередь. Проверка относится к изменению: передавать небольшие shareable-сообщения, проверять весь граф через `Ractor.shareable?`, измерять цену копирования и применять `move: true` лишь при явной смене владельца.
Оставить внутри замороженного хеша изменяемую строку и проверить `Ractor.shareable?`: `false` покажет, что для передачи по ссылке нужна глубокая неизменяемость всего графа. Проверка относится к изменению: передавать небольшие shareable-сообщения, проверять весь граф через `Ractor.shareable?`, измерять цену копирования и применять `move: true` лишь при явной смене владельца.
Оставить внутри замороженного хеша изменяемую строку и проверить `Ractor.shareable?`: `false` покажет, что для передачи по ссылке нужна глубокая неизменяемость всего графа. Проверка относится к изменению: хранить дескрипторы потоков, явно ждать их через `value` или `join`, собирать ошибки в одном месте и отменять связанную работу при критичном отказе.
Отдельно проверить поток с обычным результатом, поток с исключением и поток, который не завершается: ожидание должно передавать ошибку и иметь ограничение по времени. Проверка относится к изменению: передавать небольшие shareable-сообщения, проверять весь граф через `Ractor.shareable?`, измерять цену копирования и применять `move: true` лишь при явной смене владельца.
Вопрос 30 из 30
Какой тест даст новую информацию о надёжности решения «Устойчивость к сбоям»? Оценивайте ответ целиком: обе части утверждения должны быть точными.
Отдельно проверить поток с обычным результатом, поток с исключением и поток, который не завершается: ожидание должно передавать ошибку и иметь ограничение по времени. Такой контрпример нужен для решения: хранить дескрипторы потоков, явно ждать их через `value` или `join`, собирать ошибки в одном месте и отменять связанную работу при критичном отказе.
Отдельно проверить поток с обычным результатом, поток с исключением и поток, который не завершается: ожидание должно передавать ошибку и иметь ограничение по времени. Такой контрпример нужен для решения: передавать небольшие shareable-сообщения, проверять весь граф через `Ractor.shareable?`, измерять цену копирования и применять `move: true` лишь при явной смене владельца.
Проверить размер пула относительно соединений БД и внешних лимитов: больше потоков может только увеличить очередь. Такой контрпример нужен для решения: хранить дескрипторы потоков, явно ждать их через `value` или `join`, собирать ошибки в одном месте и отменять связанную работу при критичном отказе.
Отдельно проверить поток с обычным результатом, поток с исключением и поток, который не завершается: ожидание должно передавать ошибку и иметь ограничение по времени. Такой контрпример нужен для решения: управлять точками синхронизации детерминированно и проверять конечный инвариант, повторяя сценарий на разных реализациях Ruby.
Оставить внутри замороженного хеша изменяемую строку и проверить `Ractor.shareable?`: `false` покажет, что для передачи по ссылке нужна глубокая неизменяемость всего графа. Такой контрпример нужен для решения: хранить дескрипторы потоков, явно ждать их через `value` или `join`, собирать ошибки в одном месте и отменять связанную работу при критичном отказе.