Добавление элементов в список происходит слишком медленно

#java #loops

#java #циклы

Вопрос:

У меня есть этот цикл:

 List<Integer> numbers = new ArrayList<Integer>();
 for(int x=0; x<citiesNames.size();x  ){
            List<Cities> numeroCiudades = citiesRepository.findByCity(citiesNames.get(x));
            numbers.add(numeroCiudades.size());
            //System.out.println(numeroCiudades.size());
        }
  

где citiesNames — это список строк, содержащий 16584 элемента, а findByCity — метод, в котором я передаю строку, и она выполняет поиск в базе данных соответствующих записей.
Что я хочу сделать, так это выполнить поиск по соответствующим записям каждого города, проверить количество записей и добавить количество записей в список целых чисел. Но этот цикл слишком медленный, для отображения результата требуется очень много времени. Как я могу это оптимизировать?

Комментарии:

1. Является ли возвращаемый тип citiesNames.get a String ? Возможно, оптимизация закончится citiesRepository.findByCity .

2. Вы объявляете список внутри цикла. Это совсем не кажется правильным.

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

4. В дополнение к тому, что было сказано, может иметь смысл заранее задать емкость списка. Изменение размера большого списка (которое происходит) может привести к значительному снижению производительности. Прочитайте, что такое емкость и как работает ArrayList.

5. В дополнение к @AnisR. комментарий — попробуйте извлечь все названия городов в пакете или используя разбивку на страницы, если их количество может быть значительным (100 достаточно значительным для многих случаев использования)

Ответ №1:

Я не совсем понимаю, почему вы должны «упаковывать» все города в список, когда вы могли бы создать функцию в citiesRepository, которая возвращает значение int с количеством записей, имеющихся в этом конкретном городе. (Это значительно повысило бы производительность. Таким образом, программа могла бы просто возвращать простой int вместо создания экземпляра целого класса) (Предположим, у вас есть доступ к citiesRepository).

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

Ответ №2:

Вы могли бы использовать параллельный поток, предполагая, citiesName что это обычный тип Java collections:

 citiesName.parallelStream()
          .map(citiesRepository::findByCity)
          .collect(Collectors.toList())
  

Просто остерегайтесь подводных камней параллельного потока и того, как он использует общий ForkJoinPool доступ.

Комментарии:

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

2. Согласен. Пакетная операция была бы предпочтительнее, но это не всегда осуществимо (т. Е. у вас нет контроля над DAO или удаленным API, чтобы предлагать пакетную операцию). Параллельный поток — это шаг выше цикла for.

Ответ №3:

Чтобы оптимизировать этот цикл, вам придется изменить findByCity, чтобы он мог обрабатывать все это одновременно. Если вы не можете изменить findByCity, вы всегда можете использовать параллелизм с потоками:

     int numbers[] = citiesNames.parallelStream()
            .mapToInt(c -> citiesRepository.findByCity(c).size())
            .toArray();