Направляющие разрабатывают сомнение: я должен загрузить целый словарь/таблицу в память?

Я - новичок, работающий в простом приложении для направляющих, которое переводит документ (длинная строка) от языка до другого. Словарь является таблицей условий (строка regexp, чтобы найти и занять место, и блок что ouputs занимающая место строка). Таблица является 1 миллионом записей долго.

Каждый запрос является документом, который хочет быть переведенным. В первом жестоком подходе силы я должен выполнить целый словарь против каждого запроса/документа.

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

Я знаю, что это не является самым эффективным, но словарь должен работать целый в этой точке.

1. - Если никакая эффективность не может быть получена путем реструктуризации документа и словаря (значение его не возможно создать меньшие подмножества словаря). Каков лучший подход дизайна?

2. - Вы знаете подобных проектов, что я могу извлечь уроки из?

3. - Где должен, я надеюсь изучать, как загрузить такую большую таблицу в память (кэш?) при запуске направляющих?

Любой ответ на любой из поставленных вопросов будет значительно цениться.Большое спасибо!

5
задан fjs6 24 January 2010 в 18:54
поделиться

4 ответа

Я не думаю, что ваш веб-хостер будет счастлив с таким решением. Этот скрипт

dict = {}
(0..1000_000).each do | num |
    dict[/#{num}/] = "#{num}_subst"
end

потребляет гигабайт оперативной памяти на моем MBP для хранения хэш-стола. Другой подход будет хранить ваши замены, маршала в мемкачене, чтобы вы могли (по крайней мере) хранить их через машины.

require 'rubygems'
require 'memcached'
@table = Memcached.new("localhost:11211")

retained_keys = (0..1000_000).each do | num |
  stored_blob = Marshal.dump([/#{num}/, "#{num}_subst"])
  @table.set("p#{num}", stored_blob)
end

Вам придется беспокоиться о том, чтобы держать ключи «горячими», поскольку Memcached истекает их, если они не нужны.

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

Но это должно начать:

  require "base64"

  File.open("./dict.marshal", "wb") do | file |
    (0..1000_000).each do | num |
      stored_blob = Base64.encode64(Marshal.dump([/#{num}/, "#{num}_subst"]))
      file.puts(stored_blob)
    end
  end

  puts "Table populated (should be a 35 meg file), now let's run substitutions"

  File.open("./dict.marshal", "r") do | f |
    until f.eof?
      pattern, replacement = Marshal.load(Base64.decode64(f.gets))
    end
  end

  puts "All replacements out"

, чтобы заполнить файл и загрузить каждое замещение, это требует меня:

 real    0m21.262s
 user    0m19.100s
 sys     0m0.502s

, чтобы просто загрузить Regexp и строку из файла (все миллион, штуку по частям)

 real    0m7.855s
 user    0m7.645s
 sys     0m0.105s

Итак, это 7 секунд IO накладных расходов, но вы не теряете никакой памяти (и есть огромный номер для улучшения) - Rsize составляет около 3 меев. Вы должны легко сделать его быстрее, если вы сделаете IO навалом или сделаете один файл за 10-50 замещений и загрузить их в целом. Поместите файлы на SSD или RAID, и у вас есть победитель, но вы можете сохранить свою оперативную память.

2
ответ дан 15 December 2019 в 01:01
поделиться

В режиме производства рельсы не будут перезагружать классы между запросами. Вы можете легко сохранить в памяти, надевая его в классную переменную.

Вы могли бы сделать что-то вроде:

class Dictionary < ActiveRecord::Base
  @@cached = nil
  mattr_accessor :cached

  def self.cache_dict!
    @@cached = Dictionary.all
  end
end

, а затем в Production.RB:

Dictionary.cache_dict!

для ваших конкретных вопросов:

  1. , возможно, напишите часть, которая неэффективна в C или Java или более быстрый язык
  2. Нет, извините Отказ Может быть, вы можете сделать алгоритм Mapreceuce для распределения нагрузки на серверы.
  3. См. Выше.
1
ответ дан 15 December 2019 в 01:01
поделиться

Если вы используете что-то вроде cache_fu, то вы можете использовать что-то вроде memcache, не выполняя при этом никакой работы самостоятельно. Если вы пытаетесь занести в память 1 ММ строку, то, вероятно, будет полезно использовать распределенную природу memcache.

0
ответ дан 15 December 2019 в 01:01
поделиться

Это не столько конкретный ответ на один из ваших вопросов, сколько рекомендация по процессу. Если у вас возникли (или вы ожидаете) проблемы с производительностью, вам следует использовать профилировщик с самого начала.

Ознакомьтесь с этим руководством: Как профилировать ваше приложение Rails .

Мой опыт работы с рядом платформ (ANSI C, C #, Ruby) показывает, что проблемы с производительностью очень трудно решать заранее ; скорее, вам лучше реализовать что-то, что выглядит так, как будто оно могло бы быть эффективным, а затем проводить нагрузочное тестирование с помощью профилировщика.

Затем, когда вы узнаете , на что тратите ваше время, вы можете приложить некоторые усилия для оптимизации.

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

1
ответ дан 15 December 2019 в 01:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: