2011-01-02 1 views
1

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

Наверное, не получится получить полезные ответы, но стоит попробовать.

OK Я изменил размер кучи до 768mb и все еще ничего. Существует много свободной памяти, и java.exe использует только около 300 Мб.

Теперь я профилировал его и кучу осталось около 200 МБ, что значительно ниже того, что доступно. Процессор остается на уровне 50%. Но жесткий диск начинает биться, как сумасшедший. Понятия не имею. Я собираюсь переписать все это в C#, это мое решение.

Вот код (это просто выбрасывать сценарий, не очень):

BufferedReader s = null; 
    HashMap<String, Integer> allWords = new HashMap<String, Integer>(); 
    HashSet<String> pageWords = new HashSet<String>(); 
    long[] pageCount = new long[78592]; 
    long pages = 0; 

    Scanner wordFile = new Scanner(new BufferedReader(new FileReader("allWords.txt"))); 
    while (wordFile.hasNext()) { 
     allWords.put(wordFile.next(), Integer.parseInt(wordFile.next())); 
    } 
    s = new BufferedReader(new FileReader("wikipedia/enwiki-latest-pages-articles.xml"), 50000000); 
    StringBuilder words = new StringBuilder(); 
    String nextLine = null; 
    while ((nextLine = s.readLine()) != null) { 
     if (a.matcher(nextLine).matches()) { 
      continue; 
     } 
     else if (b.matcher(nextLine).matches()) { 
      continue; 
     } 
     else if (c.matcher(nextLine).matches()) { 
      continue; 
     } 
     else if (d.matcher(nextLine).matches()) { 
      nextLine = s.readLine(); 
      if (e.matcher(nextLine).matches()) { 
       if (f.matcher(s.readLine()).matches()) { 
        pageWords.addAll(Arrays.asList(words.toString().toLowerCase().split("[^a-zA-Z]"))); 
        words.setLength(0); 
        pages++; 
        for (String word : pageWords) { 
         if (allWords.containsKey(word)) { 
          pageCount[allWords.get(word)]++; 
         } 
         else if (!word.isEmpty() && allWords.containsKey(word.substring(0, word.length() - 1))) { 
          pageCount[allWords.get(word.substring(0, word.length() - 1))]++; 
         } 
        } 
        pageWords.clear(); 
       } 
      } 
     } 
     else if (g.matcher(nextLine).matches()) { 
      continue; 
     } 
     words.append(nextLine); 
     words.append(" "); 
    } 
+3

Мне любопытно: для чего вам нужно использовать буферизованный считыватель с буфером на 50 МБ? Похоже, что это противоречит целям дизайна всей реализации Reader (которая сосредоточена на извлечении данных при ее анализе вместо того, чтобы читать весь файл ...). Лучше всего сосредоточиться на дизайне здесь ... –

+0

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

+4

Думаю, вы взяли в целом хороший совет и довели его до крайности. Этот совет может относиться к размеру буфера приложений размером 64k вместо 256 байтов или что-то в этом роде, но я, вероятно, не пойду намного больше. В любом случае ОС будет делать дополнительную буферизацию для вас, особенно для чтения файла последовательно. Создание собственного буфера приложений 50 мегабайт может быть в конечном счете контрпродуктивным, потому что вы можете использовать эту память для чего-то более значимого (и, по сути, это похоже на вас). –

ответ

1

Вы пробовали извлекать размер буфера и пытаетесь его с настройками по умолчанию?

1

Возможно, не так, что файловая буферизация не работает, но ваша программа использует достаточно памяти, чтобы ваша система виртуальной памяти была заменена на диск. Что произойдет, если вы попытаетесь уменьшить размер буфера? А как насчет большего?

+0

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

+0

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

1

Могу поспорить, что у вас заканчивается пустое место, и вы застреваете, выполняя обратную связь с GC. Вы профилировали приложение, чтобы узнать, что происходит в течение этого времени? Кроме того, попробуйте запустить с помощью -verbose: gc, чтобы увидеть сборку мусора, как это происходит. Кроме того, можно попробовать начать с большей кучей, как»

-Xms1000m -Xmx1000m

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

1

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

... 
words.append(nextLine); 
words.append(" "); 
0

Прежде чем вы предполагаете, что что-то не так с Java и чтение IO, я предлагаю вам написать простую программу, которая просто читает файл так быстро, как только может. Вы должны иметь возможность читать файл со скоростью 20 Мбайт/с, независимо от размера файла с буферизацией по умолчанию. Вы должны сделать это, разделив приложение, чтобы просто прочитать файл. Тогда вы можете сами доказать, сколько времени потребуется, чтобы прочитать файл.

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

word.substring(0, word.length() - 1) 

такое же, как

word 

таким образом, первый пункт, если и второй являются одинаковыми.