2016-11-14 2 views
1

Предположим, мы имеем следующие классы случай:Кэширование Scala Case Класс Экземпляры

abstract sealed class Tree 
case class Leaf(i: Int) extends Tree 
case class Node(left: Tree, right: Tree) extends Tree 

Каждый раз, когда мы называем случай конструктор класса, новый объект создается в памяти. Например, в коде ниже:

val a = Leaf(0) 
val b = Leaf(0) 

а и б точки к различным объектам в памяти:

a == b // true 
a eq b // false 

Я хотел бы переопределить метод «применить» классов дела, чтобы сделать их верните кешированный объект, если он уже существует, так что в минимальном примере выше «a e b b» вернет true.

Я нашел эти две связанные ответы в Stackoverflow:

Я планирую реализовать свой переопределяющий метод «apply» с кешированием таким образом, который объединяет два подхода, связанных с abo ве. Но мне интересно, есть ли альтернативные способы, которые я должен рассмотреть. Если вы знаете, можете ли вы поделиться своим решением здесь?

Кэширование экземпляров классов случаев представляется очень полезным и естественным, чтобы уменьшить потребление памяти. И тем не менее, решение, которое я планирую реализовать (на основе двух ответов, приведенных выше), кажется довольно запутанным, требуя большого кода шаблона, который будет нарушать элегантность и лаконичность классов дел. Кто-нибудь знает, если будущие версии языка Scala может позволить нам достичь кэширования экземпляра класса случай, написав что-то простое, как это:

abstract sealed class Tree 
cached case class Leaf(i: Int) extends Tree 
cached case class Node(left: Tree, right: Tree) extends Tree 

??

+1

Просто случайный вопрос, вы видели это «кеширование» в качестве основной функции на любом другом языке? По крайней мере, я еще не сталкивался с этим. –

+0

Я тоже. И это заставляет меня задаться вопросом, есть ли причины для этого. @ Ответ Алексея Романова ниже указывает на некоторые интересные причины. – Bruno

ответ

2

Кэширование экземпляров классов случаев кажется очень полезным и естественным, чтобы уменьшить потребление памяти.

Обратите внимание, что это даже отдаленно не автоматическое улучшение, и очень многое зависит от использования шаблона класса дела (а не только ваш, но любой, кто использует свою библиотеку):

  1. You необходимо учитывать потребности в кеш-памяти и неспособность собирать экземпляры мусора, ссылающиеся на кеш (обратите внимание, что использование WeakHashMap не поможет: для этого требуется, чтобы «объекты значения не ссылались прямо на свои собственные ключи, прямо или косвенно»,).

  2. Если ключи являются примитивами (как в Leaf), они должны быть помещены в бокс перед поиском, который часто уже является вызовом конструктора.

  3. Поиск на карте значительно медленнее, чем тривиальный вызов конструктора.

  4. Анализ эвакуации часто гарантирует, что объекты на самом деле не построены, при этом убедитесь, что ваша программа работает , как будто они были. Конечно, кеширование гарантирует, что объекты сделать побег.

Но пренебрегая все, что вы можете написать макрос аннотацию, который позволит вам @cached case class Leaf(i: Int) extends Tree и генерировать код, который вы хотите (или по крайней мере @cachedcase class, я не уверен, что если вы будете в состоянии отменить apply в противном случае) , Из-за вышеизложенного я просто не ожидал, что это станет частью языка в ближайшее время.

+0

Это хорошие моменты в целом, хотя некоторые из них не применяются к моей конкретной схеме использования. Не могли бы вы рассказать о своей точке 4? Как узнать, когда новый объект не будет создан? Где я могу узнать больше об этом? – Bruno

+0

Не могли бы вы предоставить минимальный пример с аннотацией макроса @cachedcase? – Bruno

+1

Для получения основного объяснения см. Http://docs.oracle.com/javase/7/docs/technotes/guides/vm/performance-enhancements-7.html#escapeAnalysis. Идея состоит в том, что если объект используется только во время метода и не «убегает», его можно устранить, заменив все поля на локальные переменные. Но проверка того, устранено ли какое-либо конкретное выделение, далека от тривиального (и, во всяком случае, требует, чтобы JIT ударился, поэтому попытка его некогда не будет работать). См. http://psy-lob-saw.blogspot.se/2014/12/the-escape-of-arraylistiterator.html. –