2015-11-05 3 views
-1

Я возвращаю массив список формы объекта и использования его в другом. Приложение является многопоточным, и каждый поток заполняет список массивов по одному int за раз из файла, поэтому каждый add - это доступ к списку массивов. Есть 200 потоков с файлом в 1 миллион ints каждый. Для выполнения приложения требуется несколько часов, и я полагаю, что это моя шея бутылки, так как, когда я тестирую локальный список массивов, это занимает 4 минуты. Моя проблема заключается в том, что это используется везде, и мне нужно синхронизировать список массивов. Есть ли быстрое решение этой проблемы или я должен сделать так, чтобы каждый поток имел свой собственный список массивов и не возвращал его?Java возвращает ArrayList Slow?

На самом деле я был неправ, его единственный, когда массив является локальным для метода, который быстрее в любом месте, как объявлено в верхней части класса, требуется несколько часов, чтобы я работал.

Мой обратный код выглядит следующим образом:

synchronized public ArrayList<Integer> getData() 
{ 
    return this.myData; 
} 

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

Scanner scanner = new Scanner(filePath); 

    /* 
    * While we have data keep reading 
    * when out of data the simulation is complete. 
    */ 
    while (scanner.hasNext()) 
    { 
     /* 
     * Get the data to simulate requests 
     * and feed it to the algorithm being evaluated. 
     */ 
     if (scanner.hasNextInt()) 
     { 
      int temp = scanner.nextInt(); 
      //System.out.println(this.tClientName+" "+temp); 


      /* 
      * Add the temp value from incoming stream. 
      * 
      * todo:: UNLESS its NOT found on the client as a miss 
      */ 
      tClientCache.getCache().add(temp); 

     } 
     else 
     { 
      scanner.next(); 
     } 
    }//END Of while (scanner.hasNext()) 
    /* 
    * Close the scanner 
    */ 
    scanner.close(); 
+0

Замените этот 'ArrayList', который не поддерживает синхронизацию с помощью' BlockingQueue'. Кроме того, проверьте, есть ли у вас синхронизированный метод, который может замедлить ваше приложение. –

+5

Профиль, не догадываюсь. – Durandal

+0

«один int за раз из файла» - почему? не могут ли они собирать все данные из файлов и только потом добавлять их в список с помощью addAll (...)? Было бы намного быстрее. Дайте нам больше кода и объясните это лучше, если вы хотите получить какую-либо помощь ... – WFranczyk

ответ

0

Если одновременно функция выглядит следующим образом:

Scanner scanner = new Scanner(filePath); 

while(scanner.hasNext()) { 
    if(scanner.hasNextInt()) { 
     int temp = scanner.nextInt(); 
     tClientCache.getCache().add(temp); 
    } else { 
     scanner.next(); 
    } 
} 

scanner.close(); 

можно синхронизировать с помощью общего объекта синхронизации:

Scanner scanner = new Scanner(filePath); 
Object syncObject = tClientCache.getSynchronizationObject(); 
ArrayList<Integer> list = tClientCache.getCache(); 

while(scanner.hasNext()) { 
    if(scanner.hasNextInt()) { 
     int temp = scanner.nextInt(); 
     // synchronise manipulation 
     synchronized(syncObject) { 
      list.add(temp); 
     } 
    } else { 
     scanner.next(); 
    } 
} 

scanner.close(); 

и расширить CacheClient следующим:

class CacheClient { 
    ... 
    public Object getSynchronizationObject() { return m_syncObj; } 
    ... 
    private Object m_syncObj = new Object(); // For synchronised access to the cache. 
} 

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

Scanner scanner = new Scanner(filePath); 
int threshold = ... 

while(scanner.hasNext()) { 
    if(scanner.hasNextInt()) { 
     int temp = scanner.nextInt(); 
     bulk.add(temp); 
     // instead of an arbitrary threshold, why not merge the array of a whole file? 
     if(bulk.size() >= threshold) { 
      tClientCache.process(bulk); 
      bulk.clear(); 
     } 
    } else { 
     scanner.next(); 
    } 
} 
if(!bulk.isEmpty()) { 
    tClientCache.process(bulk); 
} 

scanner.close(); 

и выполнить синхронизацию в ClientCache.process:

class ClientCache { 
    ... 
    public void process(ArrayList<Integer> bulk) { 
     // synchronise cache manipulation 
     synchronized(getSynchronizationObject()) { 
      // merge howsoever you like... 
      getCache().addAll(bulk); 
     } 
    } 
} 

200 Mio int не много данных для существующих систем (< 1 Гб), но 200 Mio Integer это about 3 GB! В зависимости от того, какую обработку вы выполняете по этим данным, доступ к памяти может полностью разрушить вашу производительность: снова, если возможно, выполните обработку объемных данных, и если вам нужно делать высокопроизводительные вещи, такие как сортировка, подумайте о копировании массивов данных в фиксированный размер int[], выполните сортировку по базовому массиву типов, затем снова объедините эти объемы обратно в свои массивы.

+0

У меня устало что-то вроде этого, кроме того, что я использовал отдельный объект синхронизации для обработки файлов, но вижу, что вы возвращаетесь с наличных? –

+0

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

+0

@DixonSteel как вы обрабатываете массив? обрабатываете ли вы его, пока он заполняется? – BeyelerStudios

0

вопрос является почти наверняка не будет возвращать ArrayList, так как это просто возвращает ссылку.

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

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

Вообще у вас есть два варианта:

  • уменьшить количество точек синхронизации (то есть синхронизации реже) или
  • выбрать более эффективный механизм синхронизации.

Возможно, ваши потоки могут собрать ряд результатов и разместить их навалом (скажем, тысяча за раз)? Или вы можете переключиться на более многопоточную структуру данных (CopyOnWriteArrayList приходит на ум, но это оптимизировано для частого чтения и очень редкого письма, поэтому, вероятно, не для вашего случая использования).

+0

Я мог бы, но мне нужно кормить их поодиночке. –

Смежные вопросы