скорость scala при использовании метода get () для хеш-таблиц? (генерируются ли временные объекты Option ()?) - PullRequest
2 голосов
/ 12 октября 2011

Я конвертирую некоторый код в Scala.Это код, который находится во внутреннем цикле с очень большими объемами данных, поэтому он должен быть быстрым, и он включает поиск ключей в хэш-таблице и вычисление вероятностей.Он должен делать разные вещи в зависимости от того, найден ключ или нет.Код будет выглядеть так, используя «стандартную» идиому:

counts.get(word) match {
  case None => {
    WordDist.overall_word_probs.get(word) match {
      case None => (unseen_mass*WordDist.globally_unseen_word_prob
                    / WordDist.num_unseen_word_types)
      case Some(owprob) => unseen_mass * owprob / overall_unseen_mass
    }
  }
  case Some(wordcount) => wordcount.toDouble/total_tokens*(1.0 - unseen_mass)
}

, но я обеспокоен тем, что этот код будет очень медленным из-за того, что все эти временные объекты Some () создаются, а затемсборщиком мусора.В книге Scala2e утверждается, что умная JVM «может» оптимизировать их так, чтобы код работал правильно с точки зрения эффективности, но действительно ли это происходит с использованием Sun JVM?Кто-нибудь знает?

Ответы [ 2 ]

2 голосов
/ 12 октября 2011

Это может произойти, если вы включите escape анализ в jvm, включенном с помощью:

-XX:+DoEscapeAnalysis

на JRE 1.6. По сути, он должен обнаруживать создаваемые объекты, которые не выходят за рамки активации метода, и либо размещать их в стеке, либо собирать их сразу после того, как они больше не нужны.

Одна вещь, которую вы могли бы сделать, это выполнить микро-тестирование кода с помощью черты scala.testing.Benchmark. Просто расширьте его с помощью одноэлементного объекта и реализуйте метод run, скомпилируйте его и запустите. Он будет запускать метод run несколько раз и измерять время выполнения.

1 голос
/ 13 октября 2011

Да, будет создано Some объектов (None - одиночный).Если, конечно, JVM не исключит, что это зависит от многих факторов, в том числе от того, считает ли JVM, что код все-таки называется кодом.В этом есть даже мем: когда-то один опытный разработчик Scala написал такой код, когда другой ответил: «Что это? Любительский час? Плоская карта, которая д * т!»d переписать его:

( counts 
  get word
  map (_.toDouble / total_tokens * (1.0 - unseen_mass))
  getOrElse (
    WordDist.overall_word_probs
    get word
    map (unseen_mass * _ / overall_unseen_mass)
    getOrElse (unseen_mass * WordDist.globally_unseen_word_prob
                / WordDist.num_unseen_word_types)
  )
)

Затем вы можете выполнить рефакторинг этого - оба параметра getOrElse могут быть разделены в другом методе с хорошими именами.Поскольку они просто возвращают значение без ввода, они должны быть довольно быстрыми.

Теперь мы вызовем здесь только два метода на Option: map и getOrElse.Вот начало их реализации:

@inline final def map
@inline final def getOrElse

Поскольку параметр в getOrElse передается по имени, он включает создание анонимной функции.И, конечно же, параметр map также является функцией.Кроме этого, вероятность того, что эти методы будут встроены, довольно велика.

Итак, вот переработанный код, хотя я не знаю достаточно об этом, чтобы дать хорошие имена.

def knownWordsFrequency = counts get word map computeKnownFrequency
def computeKnownFrenquency = 
  (_: Int).toDouble / total_tokens * (1.0 - unseen_mass)

def probableWordsFrequency = (
  WordDist.overall_word_probs 
  get word 
  map computeProbableFrequency
)
def computeProbableFrequency = unseen_mass * (_: Double) / overall_unseen_mass

def unknownFrequency = (unseen_mass * WordDist.globally_unseen_word_prob
  / WordDist.num_unseen_word_types)

def estimatedWordsFrequency = probablyWordsFrequency getOrElse unknownFrequency

knownWordsFrequency getOrElse estimatedWordsFrequency
...