Производительность Java с использованием параллелизма - PullRequest
2 голосов
/ 09 августа 2010
  1. Как я могу улучшить производительность этот кусок кода?
  2. Каким будет модульный тест для данной задачи?

Код:

    public class SlowDictionary {
        private final Map<String,String> dict = new HashMap<String,String>();
        public synchronized String translate (String word)
        throws IllegalArgumentException {
            if (!dict.containsKey(word)) {
                throw new IllegalArgumentException(word + " not found.");
            }
            return dict.get(word);
        }

        public synchronized void addToDictionary (String word, String translation) 
            throws IllegalArgumentException {
            if (dict.containsKey(word)) {
                throw new IllegalArgumentException(word + " already exists.");
            }
            dict.put(word,translation);
        }

        public synchronized Set<String> getAllWords () {    
            return dict.keySet();
        }
    }

Ответы [ 8 ]

6 голосов
/ 10 августа 2010

Первое, что вы хотите сделать, это избавиться от всех синхронизированных ключевых слов.

Самый простой способ сделать это - объявить dict как ConcurrentHashMap:

private final ConcurrentMap<String,String> dict = new ConcurrentHashMap<String,String>();

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

 public String translate (String word) throws IllegalArgumentException { ..

Причиной этого является договор, по которому CCHM имеет право на получение обновлений.

Наконец, добавление в словарь может выглядеть так:

 public void addToDictionary (String word, String translation) throws IllegalArgumentException {
            if (dict.putIfAbsent(word,translation)!=null) {
                throw new IllegalArgumentException(word + " already exists.");
            }
        }

Также удаляет синхронизированные из getAllWords.

Редактировать: Подумав над комментарием Тома. Двойной взгляд в этом «исключительном случае», вероятно, не стоит того. Если дело не выдает исключение, тогда это будет уместно.

3 голосов
/ 10 августа 2010

Сброс всех ключевых слов synchronized и определение dict как ConcurrentHashMap, возможно, стоит попробовать.

1 голос
/ 10 августа 2010

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

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

public class SlowDictionary { 
    private final ConcurrentMap<String,String> dict = new ConcurentHashMap<String,String>(); 

    public String translate (String word) throws IllegalArgumentException { 
        String translation = dict.get(word);
        if (translation == null) 
            throw new IllegalArgumentException(word + " not found."); 
        return translation; 
    } 

    public void addToDictionary (String word, String translation) throws IllegalArgumentException { 
        if (dict.putIfAbsent(word, translation) != null) 
            throw new IllegalArgumentException(word + " already exists."); 
    } 

    public Set<String> getAllWords () {     
        return dict.keySet(); 
    } 
}
1 голос
/ 10 августа 2010

Когда вы говорите, улучшить производительность, у вас есть какие-либо представления о статистике использования?Например, сколько записей в операции чтения и насколько велика внутренняя карта?

Если число операций чтения пропорционально велико и карта заполняется в основном при запуске (и не огромна), выполняется копирование-запись стратегия может быть вашей лучшей ставкой.Мы использовали (и поддерживаем) CopyOnWriteMap , который имеет лучшую производительность для одновременных операций чтения, чем ConcurrentHashMap (примерно на 10% в наших тестах).

1 голос
/ 10 августа 2010
  1. Создание и выдача исключений происходит медленно, поэтому не делайте этого.
  2. Убедитесь, что вы используете только одну операцию карты в каждом методе, а не удваиваете поиск.
  3. При значительном одновременном использовании используйте ConcurrentHashMap вместо synchronized.

Обратите внимание, что метод getAllWords не является поточно-ориентированным, или, по крайней мере, Set, который возвращаетсянет.

0 голосов
/ 10 августа 2010

Существует лот эффективных способов хранения словарей.Использование тяжеловесных вещей, таких как объекты Java по умолчанию HashMap и String, не является одним из них.

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

Конечно, карта содержит - это O (1) ... Но размер карты, когда вы помещаете в нее миллионы строк, не равен O (1);)

Пища для размышления: определение наличия слова с использованием, скажем, Trie, вероятно, будет быстрее, чем простое вычисление хеш-кода String (я не говорю, что trie - это то, что вам нужно:все, что я говорю: есть больше, чем «давайте используем HashMap, это O (1), поэтому вы не можете победить это» -meets-the-eye.

И яможет сказать вам, что, скажем, Google 'translate' и Google 'find-as-you-type' определенно не реализованы путем хранения миллионов объектов Java String в I-need-constant-resizing-and-I-resizeочень медленно Java HashMaps.

Каковы ваши требования? Сколькоords?Сколько языков нужно поддерживать?

0 голосов
/ 10 августа 2010

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

0 голосов
/ 10 августа 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...