Имеет ли использование Rc<Cell<Option<T>>> ту же стоимость, что и Rc<RefCell<T>>?

я знаю, что использование RefCell требует затрат во время выполнения, а также я узнал, что можно избежать его использования, заменив его на Cell<Option<T>> или Cell<T>(T impl Default) и используя take или replace, чтобы получить экземпляр, изменить его, а затем вернуть обратно.

но есть и некоторые затраты: мне нужно обернуть T с помощью Some и использовать if let Some(t) и .set(Some(t)), чтобы получить и положить его обратно. я не знаю, стоит ли заменять RefCell на Cell<Option>

Короткий ответ. Нет. Просто используйте RefCell. Он ясно показывает ваше намерение реализовать проверку заимствований и перенести ее в среду выполнения, а также имеет несколько более удобных API. Cell был создан для чего-то другого. Таким образом, хотя вы можете использовать его так, как вы описали, это будет неэргономично, сбивает с толку других и, вероятно, приведет к большему потреблению памяти.

Aleksander Krauze 24.06.2024 06:57

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

Aleksander Krauze 24.06.2024 07:06
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
0
2
75
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Суть: RefCell<T> более гибок и прост в использовании, имеет меньше ошибок. В большинстве ситуаций он будет превосходить или работать не хуже Cell<Option<T>>. Его следует использовать до тех пор, пока не будет доказано, что небольшой размер накладных расходов является проблемой (по результатам теста!)

вариант использования RefCell<T>Cell<Option<T>>Cell<T: Default> доступ с общий: borrow()
эксклюзивный: borrow_mut() общий: невозможно
эксклюзивный: take() общий: невозможно (только первый take получает реальное значение и только последний replace вступает в силу
эксклюзивный: take() доступ к производительности должен проверить, доступно ли значение, и обновить целое число необходимо проверить, доступно ли значение, и заменить Some(t) на None необходимо использовать T::default() для замены взятого значения, что может быть дорогостоящим доступ проверен всегда всегда (Option — это None, когда значение извлекается) никогда, в результате две параллельные ветки могут иметь значение, и обновления любой из ветвей могут быть пропущены. одновременный доступ может раздавать несколько общих ссылок одновременно невозможно невозможно (второй доступ получит только T::default() и не сможет узнать) высвобождение значения автоматически, когда Ref/RefMut отбрасывается, когда он выходит за пределы области видимости, или вручную, dropпингуя его надо не забыть использовать replace надо не забыть использовать replace производительность выпуска ценности уменьшить целое число замените None на Some(t)T::drop что может быть дорого размер всегда дополнительный указатель на всю ширину, который отслеживает, сколько Ref/RefMut находится в обращении обычно требуется количество байтов, равное выравниванию T дополнительно для дискриминанта, или вообще никаких дополнительных затрат на размер, если T имеет нишу, которую Option можно использовать нет накладных расходов на размер

Подводя итог, можно сказать, что да, вы можете избежать использования RefCell, но вы все равно понесете затраты во время выполнения. Вряд ли она будет даже больше, чем небольшая стоимость RefCell. Единственное, на чем иногда можно сэкономить, — это накладные расходы на размер в одну ширину указателя, который отслеживает количество Ref[Mut] в обращении.

Другие вопросы по теме